最終更新:ID:OhG22C3YuA 2011年02月23日(水) 13:06:51履歴
以下のコードがUIスレッド上から呼び出されると、worker.DoWorkはUIスレッドとは別スレッドで動作する。
一方、worker.RunWorkerCompletedとProgressChanged はUIスレッド(workerを作ったスレッド)で実行される。
WPFはUIスレッドでしかコントロールのプロパティを変更できないので、RunWorkerCompletedとProgressChangedをうまく使うと楽できそうだ。
一方、worker.RunWorkerCompletedとProgressChanged はUIスレッド(workerを作ったスレッド)で実行される。
WPFはUIスレッドでしかコントロールのプロパティを変更できないので、RunWorkerCompletedとProgressChangedをうまく使うと楽できそうだ。
private void Button_Click(object sender, RoutedEventArgs e) { Console.WriteLine("ButtonClick: " + Thread.CurrentThread.ManagedThreadId); var worker = new BackgroundWorker(); worker.WorkerReportsProgress = true; worker.DoWork += (s, arg) => { for (int i = 0; i < 3; i++) { Console.WriteLine(string.Format("DoWork{0}: {1}", i, Thread.CurrentThread.ManagedThreadId)); worker.ReportProgress(i); } }; worker.ProgressChanged += (s, arg) => { Console.WriteLine(string.Format("ProgressChanged{0}: {1}" , arg.ProgressPercentage, Thread.CurrentThread.ManagedThreadId)); }; worker.RunWorkerCompleted += (s, arg) => { Console.WriteLine("Completed: " + Thread.CurrentThread.ManagedThreadId); }; worker.RunWorkerAsync(); }出力は
ButtonClick: 10 DoWork0: 7 DoWork1: 7 DoWork2: 7 ProgressChanged0: 10 ProgressChanged1: 10 ProgressChanged2: 10 Completed: 10
public partial class App : Application { private class MyWorker : BackgroundWorker { private string _name; public MyWorker(string name) { _name = name; } protected override void OnDoWork(DoWorkEventArgs e) { Debug.WriteLine(string.Format("Worker {0} DoWork called", _name)); System.Threading.Thread.Sleep(100); Debug.WriteLine(string.Format("Worker {0} DoWork finished", _name)); } protected override void OnRunWorkerCompleted(RunWorkerCompletedEventArgs e) { Debug.WriteLine(string.Format("Worker {0} WorkerCompleted called", _name)); System.Threading.Thread.Sleep(100); Debug.WriteLine(string.Format("Worker {0} WorkerCompleted finished", _name)); } } private BackgroundWorker[] _workers; protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); _workers = new BackgroundWorker[10]; for (int i = 0; i < 10; i++) { _workers[i] = new MyWorker(i.ToString()); } foreach (var w in _workers) w.RunWorkerAsync(); System.Console.ReadLine(); } }
Worker 0 DoWork called Worker 1 DoWork called Worker 2 DoWork called Worker 3 DoWork called Worker 0 DoWork finished Worker 1 DoWork finished Worker 2 DoWork finished Worker 5 DoWork called Worker 4 DoWork called Worker 6 DoWork called Worker 3 DoWork finished Worker 7 DoWork called Worker 0 WorkerCompleted called Worker 5 DoWork finished Worker 7 DoWork finished Worker 4 DoWork finished Worker 6 DoWork finished Worker 8 DoWork called Worker 9 DoWork called Worker 0 WorkerCompleted finished Worker 1 WorkerCompleted called Worker 8 DoWork finished Worker 9 DoWork finished Worker 1 WorkerCompleted finished Worker 2 WorkerCompleted called Worker 2 WorkerCompleted finished Worker 3 WorkerCompleted called Worker 3 WorkerCompleted finished Worker 5 WorkerCompleted called Worker 5 WorkerCompleted finished Worker 7 WorkerCompleted called Worker 7 WorkerCompleted finished Worker 4 WorkerCompleted called Worker 4 WorkerCompleted finished Worker 6 WorkerCompleted called Worker 6 WorkerCompleted finished Worker 8 WorkerCompleted called Worker 8 WorkerCompleted finished Worker 9 WorkerCompleted called Worker 9 WorkerCompleted finished
- RunWorkerAsync()を読んだ順番に実行されるとは限らない
- DoWorkは並列で実行されるが、WorkerCompletedは並列で実行されない(ほかが完全に終了してから)
- つまり、WorkerCompletedはSleepするとUIスレッド自体をSleepさせるのでやってはいけない。(意図的にやるのならいいかもしれない)
要するに、以下のようなコードを書いてはダメだと言うこと(汗
AutoResetEvent ev = new AutoResetEvent(false); BackgroundWorker worker = new BackgroundWorker(); worker.DoWork += delegate { //時間のかかる処理 }; worker.RunWorkerCompleted += delegate { ev.Set(); }; worker.RunWorkerAsync(); ev.WaitOne(); //workerが終了してから、これ以降の処理を継続したいほかのスレッドで重い処理をしてから、完了後続きの処理をやろうとして書いたコードだけど、*1
別にWaitOne()しているあいだディスパッチャがUIスレッドで別の処理をやってくれる訳じゃない。
RunWorkerCompletedが呼ばれるのは、その外のスレッドと同じ。
つまりWaitOne()で止まっているスレッドなので、RunWorkerCompletedは永遠に呼ばれることはない。
ちゃんとわかっていればあたりまえかもしれないけど、
うっかりしててはまったので一応メモとして書いておきます。
このページへのコメント
i4kmFD <a href="http://zpyjtbngbfwk.com/">zpyjtbngbfwk</a>, [url=http://uyyyvntrlxsb.com/]uyyyvntrlxsb[/url], [link=http://pwzkjtbpjuon.com/]pwzkjtbpjuon[/link], http://aiqbdpbhrbsj.com/