web-dev-qa-db-ja.com

System.Timers.TimerとSystem.Threading.Timerのスレッドセーフ

この記事の内容: http://msdn.Microsoft.com/en-us/magazine/cc164015.aspx 作者はSystem.Threading.Timerがスレッドセーフ

それ以来、これはブログ、リヒターの本「CLR via C#」でSOで繰り返されましたが、これが正当化されることは決してありません。

さらに MSDNのドキュメント は、「このタイプはスレッドセーフである」ことを保証します。

1)真実を言うのは誰ですか?

2)これが元の記事である場合、System.Threading.Timerがスレッドセーフにならない理由とそのラッパー System.Timers.Timerは、より多くのスレッドセーフを実現しますか?

ありがとう

23
Pragmateek

いいえ、それはそれが機能する方法ではありません。 .NET非同期Timerクラスは完全にスレッドセーフです。スレッドセーフの問題は、推移的なプロパティではなく、スレッドセーフに実行されるotherコードを作成しないことです。 .NET Frameworkプログラマーではなく、作成したコード。

これは、Windows UIコードが基本的にスレッドセーフではないという非常に一般的な仮定による同じ種類の問題です。 Windows内のコードは完全にスレッドセーフです。問題は、実行されるすべてのコード、つまりnot Windowsの一部であり、Microsoftプログラマーによって作成されたものではありません。 SendMessage()呼び出しによってトリガーされるそのコードのlotは常に存在します。プログラマが書いたカスタムコードを実行します。または、ユーティリティによってインストールされたフックのように、彼が作成しなかったコード。プログラムが難しいことはなく、1つのスレッドでメッセージハンドラを実行することを前提とするコード。彼は通常そうしますが、そうしないとlotの問題が発生します。

System.Timers.Timer.ElapsedイベントとSystem.Threading.Timerコールバックでも同じ問題が発生します。プログラマはlotsでそのコードの記述を間違えます。これは、任意のスレッドプールスレッドで非同期的に完全に実行されます。共有変数に触れると、実際に状態を保護するためにロックが必要になります。見落としやすい。さらに悪いことに、前の呼び出しが実行を停止する前に、コードが実行されたときに再びになると、非常に簡単にトラブルの山に陥ります。タイマー間隔が短すぎるか、マシンの負荷が高すぎる場合にトリガーされます。これで、同じコードを実行するtwoスレッドができました。

スレッド化は難しい、11時のニュース。

46
Hans Passant