『プログラミング C#』という本には、次のようなサンプル コードがいくつか掲載されていますSynchronizationContext
。
SynchronizationContext originalContext = SynchronizationContext.Current;
ThreadPool.QueueUserWorkItem(delegate {
string text = File.ReadAllText(@"c:\temp\log.txt");
originalContext.Post(delegate {
myTextBox.Text = text;
}, null);
});
私はスレッドの初心者なので、詳しく答えてください。まず、コンテキストが何を意味するのか、プログラムは に何を保存するのかがわかりません。originalContext
また、メソッドが起動されるとPost
、UI スレッドはどの
ような処理を行いますか? 馬鹿げた質問をしていたら、訂正してください。よろしくお願いします!
編集: たとえば、myTextBox.Text = text;
メソッドにだけ記述した場合、違いは何でしょうか?
ベストアンサー1
SynchronizationContext は何をしますか?
簡単に言えば、SynchronizationContext
コードが実行される可能性のある場所を表します。Send
またはPost
方法その場所で が呼び出されます。 (Post
は の非ブロッキング/非同期バージョンですSend
。)
すべてのスレッドは、SynchronizationContext
それに関連付けられたインスタンスを持つことができます。実行中のスレッドは、静的SynchronizationContext.SetSynchronizationContext
メソッド実行中のスレッドの現在のコンテキストは、SynchronizationContext.Current
財産。
先ほど書いたように(各スレッドには同期コンテキストが関連付けられている)、aはSynchronizationContext
必ずしもaを表すわけではない。特定のスレッド; また、渡されたデリゲートの呼び出しを転送することもできますいくつかのうちのいずれかスレッド(例えば、ThreadPool
ワーカースレッド、または(少なくとも理論上は)特定のCPUコア、あるいは別のネットワークホストデリゲートが実行される場所は、使用されるタイプによって異なりますSynchronizationContext
。
Windows フォームは、最初のフォームが作成されたスレッドに をインストールしますWindowsFormsSynchronizationContext
。(このスレッドは一般に「UI スレッド」と呼ばれます。) このタイプの同期コンテキストは、渡されたデリゲートをまさにそのスレッドで呼び出します。Windows フォームは、他の多くの UI フレームワークと同様に、コントロールの操作をそれらが作成されたのと同じスレッドでのみ許可するため、これは非常に便利です。
myTextBox.Text = text;
メソッド内に記述するだけで違いは何でしょうか?
渡したコードはThreadPool.QueueUserWorkItem
スレッド プールのワーカー スレッドで実行されます。つまり、myTextBox
作成されたスレッドでは実行されないため、Windows フォームは遅かれ早かれ (特にリリース ビルドの場合)、myTextBox
別のスレッドからアクセスできないことを通知する例外をスローします。
myTextBox
このため、その特定の割り当ての前に、何らかの方法でワーカー スレッドから「UI スレッド」(作成された場所) に「切り替える」必要があります。これは次のように行われます。
UI スレッドにいる間に、Windows フォームをキャプチャし、後で使用するために
SynchronizationContext
その参照を変数 ( ) に格納します。この時点でクエリを実行する必要があります。 に渡されたコード内でクエリを実行すると、スレッド プールのワーカー スレッドに関連付けられている同期コンテキストが取得される可能性があります。Windows フォームのコンテキストへの参照を格納すると、いつでもどこでもそれを使用して、UI スレッドにコードを「送信」できます。originalContext
SynchronizationContext.Current
ThreadPool.QueueUserWorkItem
UI 要素を操作する必要があるときはいつでも (ただし、UI スレッド上にない場合、または UI スレッド上にない可能性がある場合)、 を介して Windows フォームの同期コンテキストにアクセスし
originalContext
、UI を操作するコードを または に渡しSend
ますPost
。
最後にコメントとヒント:
同期コンテキストとはしませんが代わりに行うことは、特定の場所/コンテキストで実行する必要があるコードと、 に渡さずに通常どおり実行できるコードを通知することです
SynchronizationContext
。これを決定するには、プログラミング対象のフレームワーク (この場合は Windows フォーム) のルールと要件を知っておく必要があります。Windowsフォームのこの簡単なルールを覚えておいてください。コントロールやフォームには、それを作成したスレッド以外からアクセスしないでください。どうしてもアクセスする必要がある場合は、
SynchronizationContext
上記のメカニズムを使用するか、Control.BeginInvoke
(これは、まったく同じことを実行する Windows フォーム固有の方法です)。.NET 4.5以降でプログラミングしている場合は、、、などを明示的に使用するコードを新しいものに変換することで、作業がはるかに簡単になります
SynchronizationContext
。ThreadPool.QueueUserWorkItem
control.BeginInvoke
async
/await
キーワードそしてそのタスク並列ライブラリ (TPL)、つまり、Task
そしてTask<TResult>
クラス。これらは、UI スレッドの同期コンテキストをキャプチャし、非同期操作を開始し、その後 UI スレッドに戻って操作の結果を処理できるようにするという作業を非常に高いレベルで処理します。