まず、ほとんどのクラスはスレッドセーフである必要はありません。YAGNIを使用します。実際に使用する(そしてテストする)ことがわかっている場合にのみ、スレッドセーフを適用します。
メソッドレベルのものについては[MethodImpl]
:
[MethodImpl(MethodImplOptions.Synchronized)]
public void SomeMethod() {/* code */}
これは、アクセサー(プロパティおよびイベント)でも使用できます。
private int i;
public int SomeProperty
{
[MethodImpl(MethodImplOptions.Synchronized)]
get { return i; }
[MethodImpl(MethodImplOptions.Synchronized)]
set { i = value; }
}
フィールドのようなイベントはデフォルトで同期されますが、自動実装されたプロパティはそうではありません:
public int SomeProperty {get;set;} // not synchronized
public event EventHandler SomeEvent; // synchronized
個人的には、MethodImpl
ロックthis
またはの実装が好きではありませんtypeof(Foo)
。これはベストプラクティスに反します。推奨されるオプションは、独自のロックを使用することです。
private readonly object syncLock = new object();
public void SomeMethod() {
lock(syncLock) { /* code */ }
}
フィールドのようなイベントの場合、ロックの実装はコンパイラに依存することに注意してください。古いMicrosoftのコンパイラではあるlock(this)
/ lock(Type)
しかし、 - より最近のコンパイラでは、それが使用するInterlocked
アップデートを-スレッドセーフな厄介な部分のないようにします。
これにより、よりきめ細かい使用が可能になり、Monitor.Wait
/ Monitor.Pulse
などを使用してスレッド間で通信できます。
関連するブログエントリ(後で再検討)。