この質問に答える際に、私が確信していなかったOPの状況についてのさらなる質問が出てきました。それは主にプロセッサアーキテクチャの質問ですが、C++11メモリモデルについてのノックオンの質問もあります。
基本的に、OPのコードは、次のコードのために、より高い最適化レベルで無限にループしていました(簡単にするために少し変更されています)。
while (true) {
uint8_t ov = bits_; // bits_ is some "uint8_t" non-local variable
if (ov & MASK) {
continue;
}
if (ov == __sync_val_compare_and_swap(&bits_, ov, ov | MASK)) {
break;
}
}
__sync_val_compare_and_swap()
GCCのアトミックCASはどこに組み込まれていますか。GCCは、ループに入る前にbits_ & mask
検出された場合true
、CAS操作を完全にスキップして、これを(合理的に)無限ループに最適化したので、次の変更を提案しました(これは機能します)。
while (true) {
uint8_t ov = bits_; // bits_ is some "uint8_t" non-local variable
if (ov & MASK) {
__sync_synchronize();
continue;
}
if (ov == __sync_val_compare_and_swap(&bits_, ov, ov | MASK)) {
break;
}
}
私が答えた後、OPはに変更bits_
することvolatile uint8_t
もうまくいくようだと述べました。volatile
通常は同期に使用されるべきではないので、そのルートに進まないことを提案しました。とにかく、ここでフェンスを使用することにはそれほどマイナス面はないようです。
しかし、私はそれについてもっと考えました、そしてこの場合、それがov & MASK
無期限に古くなった値に基づいていない限り(すなわち、更新の実際の試行bits_
が同期されるため、ループは最終的に壊れます)。したがって、既存のプロセッサのように、別のスレッドによって更新されたvolatile
場合に、このループが最終的に終了することを保証するには、ここで十分ですか?言い換えると、明示的なメモリフェンスがない場合、コンパイラによって最適化されていない読み取りが、代わりにプロセッサによって無期限に効果的に最適化されることは実際に可能ですか?(編集:bits_
bits_ & MASK == false
明確にするために、ここでは、読み取りがコンパイラーによってループで出力されるという仮定を前提として、最新のハードウェアが実際に何を行う可能性があるかを尋ねています。したがって、C ++セマンティクスで表現するのは便利ですが、技術的には言語の問題ではありません。)
これはハードウェアの角度ですが、少し更新して、C ++ 11メモリモデルについても回答可能な質問にするために、上記のコードの次のバリエーションを検討してください。
// bits_ is "std::atomic<unsigned char>"
unsigned char ov = bits_.load(std::memory_order_relaxed);
while (true) {
if (ov & MASK) {
ov = bits_.load(std::memory_order_relaxed);
continue;
}
// compare_exchange_weak also updates ov if the exchange fails
if (bits_.compare_exchange_weak(ov, ov | MASK, std::memory_order_acq_rel)) {
break;
}
}
cppreferenceは、std::memory_order_relaxed
「アトミック変数周辺のメモリアクセスの並べ替えに制約がない」ことを意味し、実際のハードウェアが実行するかどうかに関係なく、準拠する実装で別のスレッドで更新された後、更新された値をbits_.load(std::memory_order_relaxed)
技術的に読み取ることbits_
ができないことを意味します。 ?
編集:私はこれを標準(29.4 p13)で見つけました:
実装では、妥当な時間内にアトミックストアをアトミックロードから見えるようにする必要があります。
したがって、更新された値を「無限に長く」待つことは(ほとんど?)問題外ですが、それ以外の特定の時間間隔の鮮度が「合理的」であるという確固たる保証はありません。それでも、実際のハードウェアの動作については疑問が残ります。