大きな配列(3e9要素)のデータがあり、その値を複数のスレッドで更新しています。私は競合状態があることを知りました。データの一部をロックとして使用できますか?
要素が互いに独立しているので、関数全体をロックする必要はないと思いますが、とdata[234]
の更新は同時に安全に行うことができます。
また、data[]
の各要素の最上位ビットが決して使用されないことがわかりました。そのビットにGCC原子組み込みロックを実装するのは安全ですか?
私のコードは次のとおりですが、デッドロックが発生しているようです。
const unsigned short LOCK_MASK = 1<<15;
unsigned short * lock = &(data[position]);
unsigned short oldLock, newLock;
//lock
do {
oldLock = *lock;
newLock = oldLock^LOCK_MASK;
} while ((oldLock & LOCK_MASK) || !__sync_bool_compare_and_swap(lock, oldLock, newLock));
//update data[position] here
...
...
...
//unlock
*lock ^= LOCK_MASK;
私も(Lightweight spinlocks built from GCC atomic operations?)この記事を読んで、私の設計では、私のdata
EDITにvolatile
を追加し、0のロックが解除意味し、1つの手段は、あなたのコードは番号が含まれて
ロックを取得する前にすべての読み取りで同期が必要です。特に、 'oldLock = * lock;'は間違っています、それは原子的である必要があります。そのままでは、オプティマイザは、 '(oldLock&LOCK_MASK)'が一度真であった場合、 '* lock'が決して変更されないと想定するかもしれません。 –
より慎重なアプローチは、適切な数の実際のミューテックス(またはスピンロックまたは使用するメカニズム)を割り当て、それらを使用してデータへのアクセスを同期させることです。例えばM個のミューテックスの配列を持っている場合は、データ配列に値#iを読み書きする前に、各スレッドがmutex#(i%M)をロックするようにしてください。ミューテックスの競合が受け入れられるほど稀である最小の値を見つけるまで、Mの値を調整します。 –