まず、ロックは必要ないかもしれません。CPU が各読み取りと書き込みをアトミックに処理する型の配列を使用した読み取りと書き込みは、それ自体がスレッド セーフです (ただし、古い読み取りを避けるためにメモリ バリアを配置することをお勧めします)。
x = 34
とはいえ、整数はスレッドセーフですがそうではないのと同じようにx++
、現在の値に依存する書き込み (したがって読み取りと書き込み) がある場合、それはスレッドセーフではありません。
ロックは必要だが 50 個ほどにしたくない場合は、ストライプ化できます。ReaderWriterSlim
最初にストライプ化されたロックを設定します (小さなサンプル コードではなく単純なロックを使用します。同じ原則が適用されます)。
var lockArray = new object[8];
for(var i =0; i != lockArray.Length; ++i)
lockArray[i] = new object();
次に、それを使用するとき:
lock(lockArray[idx % 8])
{
//operate on item idx of your array here
}
これは、すべてに対して 1 つのロックのシンプルさとサイズと、要素ごとに 1 つのロックのメモリ使用量とのバランスです。
ある要素の操作が別の要素の操作に依存している場合、配列のサイズを変更する必要がある場合、または複数のロックが必要なその他の場合は、大きな問題が発生します。多くのデッドロック状況は、常に同じ順序でロックを取得することで回避できます (そのため、複数のロックを必要とする他のスレッドが、必要なロックを保持している間に、既に持っているロックを取得しようとすることはありません)。これらのケース。
また、たとえばインデックス 3 とインデックス 11 を扱っている場合は、オブジェクト 3 を 2 回ロックしないようにする必要があります (この特定の再帰的ロックがうまくいかない方法は考えられませんが、単に回避しない理由はありません)。再帰ロックが安全なケースの 1 つであることを証明する必要はありませんか?)