数日前、並列化のために WPF アプリケーションでタスクの使用を開始しました。私のアプリケーションは、5 秒ごとにいくつかの作業を実行する必要があります。この作業は 4 つのタスクで並列化する必要があります。それに加えて、タスクによる作業中に UI がフリーズするのを避けるために、バックグラウンド ワーカーを実装する必要があります。タスクがどのように機能するかを理解するための例をたくさん見つけました。ただし、タスクがタイマー、バックグラウンド ワーカー、およびもちろんロックと共にどのように機能するかを理解するための簡単な例は見つかりませんでした。私の理解に基づいて簡単な例を書きました。私がそれを正しく行っているかどうかについてアドバイスをください。このようにして、WPF でのマルチタスクについてよりよく理解できるようになります。返信をお待ちしております。
namespace timer_and_thread
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
DispatcherTimer TimerObject;
Task[] tasks;
readonly object _countLock = new object();
int[] Summ = new int[10];
int Index = 0;
int ThreadsCounter = 0;
public MainWindow()
{
InitializeComponent();
TimerObject = new DispatcherTimer();
TimerObject.Tick += new EventHandler(timer_Elapsed);
TimerObject.Interval = new TimeSpan(0, 0, 5);
}
// call the method every 5 seconds
private void timer_Elapsed(object sender, EventArgs e)
{
TimerObject.Stop();
// 4 - is the tasks' count
ThreadsCounter = 4;
Index = 0;
tasks = new Task[4];
tasks[0] = Task.Factory.StartNew(() => DoSomeLongWork());
tasks[1] = Task.Factory.StartNew(() => DoSomeLongWork());
tasks[2] = Task.Factory.StartNew(() => DoSomeLongWork());
tasks[3] = Task.Factory.StartNew(() => DoSomeLongWork());
// wait untill all tasks complete
while (ThreadsCounter != 0) ;
TimerObject.Start();
}
private void DoSomeLongWork()
{
while (Index < Summ.Length)
{
// lock the global variable from accessing by multiple threads at a time
int localIndex = Interlocked.Increment(ref Index) - 1;
//I wrote rundom number generation just a an example of doing some calculation and getting some result. It can also be some long calculation.
Random rnd = new Random();
int someResult = rnd.Next(1, 100000);
// lock the global variable (Summ) to give it the result of calculation
lock (_countLock)
{
Summ[localIndex] = someResult;
}
}
Interlocked.Decrement(ref ThreadsCounter);
return;
}
// button by which I start the application working
private void Start_Button_Click_1(object sender, RoutedEventArgs e)
{
TimerObject.Start();
}
}
}
追加の質問が 2 つあります。
バックグラウンド ワーカーの代わりにタスクを使用できますか?
私が持っているように、スレッドによるグローバル変数へのアクセスを防ぐためにロックが使用されます。ただし、スレッドで UI 要素にアクセスするには、Dispatcher を使用する必要があります。右?
Application.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(() =>
{
label1.Content = "Some text";
}));