async / awaitを使用して非同期コードを作成するとき、通常ConfigureAwait(false)
はコンテキストのキャプチャを回避するために、コードがスレッドプールスレッドから次のスレッドプールスレッドにジャンプしていawait
ます。これにより、スレッドの安全性に関する懸念が生じます。このコードは安全ですか?
static async Task Main()
{
int count = 0;
for (int i = 0; i < 1_000_000; i++)
{
Interlocked.Increment(ref count);
await Task.Yield();
}
Console.WriteLine(count == 1_000_000 ? "OK" : "Error");
}
変数i
は保護されておらず、複数のスレッドプールスレッド*によってアクセスされます。アクセスのパターンは非並行ですが、理論的には各スレッドがローカルにキャッシュされた値をインクリメントi
して、1,000,000回を超える反復が可能になるはずです。しかし、実際にはこのシナリオを作成することはできません。上記のコードは、私のマシンでは常にOKを印刷します。これは、コードがスレッドセーフであることを意味しますか?またはi
、lock
?を使用して変数へのアクセスを同期する必要があります。
(*私のテストによれば、スレッドの切り替えは平均して2回の反復ごとに発生します)
i
各スレッドにキャッシュされると思いますか?より深く掘り下げるには、このSharpLab ILを参照してください。