方法 #1:
最も単純で最も効率の悪い方法は、リーダーとライターのクリティカル セクションを作成することです。
// Writer
lock (aList)
{
aList.Remove(item);
}
// Reader
lock (aList)
{
foreach (T name in aList)
{
name.doSomething();
}
}
方法 #2:
これは方法 1 に似ていforeach
ますが、ループの全期間にわたってロックを保持する代わりに、最初にコレクションをコピーしてからコピーを反復処理します。
// Writer
lock (aList)
{
aList.Remove(item);
}
// Reader
List<T> copy;
lock (aList)
{
copy = new List<T>(aList);
}
foreach (T name in copy)
{
name.doSomething();
}
方法 #3:
それはすべて特定の状況に依存しますが、私が通常これに対処する方法は、コレクションへのマスター参照を不変に保つことです。そうすれば、リーダー側でアクセスを同期する必要はありません。ライター側にはlock
. リーダー側には何も必要ありません。つまり、リーダーは高度な並行性を維持します。あなたがする必要がある唯一のことは、aList
参照を としてマークすることですvolatile
。
// Variable declaration
object lockref = new object();
volatile List<T> aList = new List<T>();
// Writer
lock (lockref)
{
var copy = new List<T>(aList);
copy.Remove(item);
aList = copy;
}
// Reader
List<T> local = aList;
foreach (T name in local)
{
name.doSomething();
}