読み取り/書き込みのロックを回避するために、次の方法でベクトルなどのSTLコンテナーを反復処理しても安全かどうか疑問に思いますが、「書き込み」スレッドによってのみpush_back()操作を許可します。
しないでください、これはスレッドセーフではありません。値を読み取ろうとして現在のバッファーに移動しようとしているスレッドについて考えてみます。この時点で、2番目のスレッドがバッファーを拡張しており、最初のスレッドがバッファーへのポインターを取得した後、実際に値を読み取る前に、2番目のスレッドがバッファーの内容を解放します。最初のスレッドはデッドオブジェクトの読み取りですが、これは未定義の動作です。
問題を-edベクトルに制限するreserve()
(つまり、バッファーの増大の問題を回避する)アプローチは、依然としてスレッドセーフではありません。のコードは次のpush_back()
ようになります。
template <...>
class vector {
T *begin,*end,*capacity; // common implementation uses 3 pointers
void push_back(T value) {
if (end == capacity) { /* grow vector and insert */ }
else {
new (end) T(value);
++end;
}
}
};
ここでの問題は、同期メカニズムがないと、コンパイラが命令を並べ替え、インクリメントend
してメモリに格納T
し、バッファ要素に対してのコンストラクタを呼び出すことができることです。その並べ替えが発生した場合、リーダースレッドにはsize()
、現在保存されている値を含む値が表示される可能性がありますが、その値はまだベクターに含まれていません。