Monitor
は、スレッド親和性を有する。別のスレッドから終了することはできません。
しかし、とにかくここで何をしようとしているのかは不明です。あなたはすでに別の非同期メソッドを呼び出す非同期メソッドになっています。 await
を使用してください。ちょうどコンソールアプリケーションでawait
を正しく使用できるように同期コンテキストを設定してください。デッドロックを心配していない場合は、Task.Wait
を使用してください。
Monitor.Wait
については、あなたが思っていることはしません。待機は、モニターのためではなく、信号のためのものです。例:
static readonly object syncObject = new object();
void Thread1()
{
lock (syncObject) Monitor.Wait(syncObject);
}
void Thread2()
{
lock (syncObject) Monitor.Pulse(syncObject);
}
このシナリオでは、どちらの方法も別のスレッドで実行されます。 Thread1
が最初に実行されると、ロックを取り、シグナルを待って(シグナルが出るまでロックを終了します)、シグナルが与えられた後にロックを再獲得します。 Thread1
はMonitor.Pulse
メソッドを使用して信号を提供します。どちらの場合も、ロックは単一のスレッドで行われ、同じスレッドで終了されることに注意してください。
このメカニズムは、使い方が非常に簡単ではなく、やや遅いので、あまり見ないようにしています。
また、Task.Run
で使用されるスレッドはあなたのものではありません。スレッドプールスレッドでブロッキングコードを使用することは、通常は望ましくありません。作成するトレードオフを理解していることを確認してください。さらに重要なのは、タスクにはスレッドアフィニティがないからです。つまり、モニタのようなスレッドアファインの同期プリミティブを使用するのはむしろ冒険的です:)あなたの場合、外部ではなくTask.Run
の内部でロックを取ったとしても、 await
の後に別のスレッドを取得した可能性があるため、Monitor.Exit
が失敗する可能性があります。
マルチスレッドの最も難しい部分は、うまく動作しないということではなく、ほとんどの場合ほとんど動作しないという醜い傾向があります。実際にはいつも、あなたに気をつけてください)。テストでは、マルチスレッドのコードが実際にどのように動作するかについて、十分に自信を持てるほど十分ではありません。あなたが得るのは、バグを再現するのがほとんど不可能で、ほとんど不可能です。あなたはここでラッキーです - あなたのコードは確実に失敗します。それは確かにほとんどのマルチスレッドの問題ではありません:)
Joe Albahari's introduction to threadingは、あらゆる種類のマルチスレッドプログラミングの大きな助けです。私は強くそれを少なくとも1回読むことを強くお勧めします。将来の参照のためにブックマークに残してください:)
"しかし、それはいつまでもMonitor.Waitでブロックされます" - うん、そうではなく、何も 'Monitor.Pulse'を呼んでいない。なぜこれがうまくいくと思ったのかは明らかではありませんが、モニターを所有していないスレッドで 'Monitor.Exit'を呼び出すと例外がスローされます。また、特にasync/awaitを使っているメソッドでは、変数asyncを命名することを強くお勧めします。 –
あなたは正確に何をしようとしていますか? –
http://stackoverflow.com/a/21404261/6527049 –