1 つのプロデューサーによって書き込まれ、N 人のコンシューマーによって読み取られるリングバッファーがあります。これはリングバッファであるため、プロデューサーによって書き込まれるインデックスがコンシューマーの現在の最小インデックスよりも小さくても問題ありません。プロデューサーとコンシューマーの位置は、それぞれの によって追跡されCursorます。
class Cursor
{
public:
inline int64_t Get() const { return iValue; }
inline void Set(int64_4 aNewValue)
{
::InterlockedExchange64(&iValue, aNewValue);
}
private:
int64_t iValue;
};
//
// Returns the ringbuffer position of the furthest-behind Consumer
//
int64_t GetMinimum(const std::vector<Cursor*>& aCursors, int64_t aMinimum = INT64_MAX)
{
for (auto c : aCursors)
{
int64_t next = c->Get();
if (next < aMinimum)
{
aMinimum = next;
}
}
return aMinimum;
}
生成されたアセンブリ コードを見ると、次のように表示されます。
mov rax, 922337203685477580 // rax = INT64_MAX
cmp rdx, rcx // Is the vector empty?
je SHORT $LN36@GetMinimum
npad 10
$LL21@GetMinimum:
mov r8, QWORD PTR [rdx] // r8 = c
cmp QWORD PTR [r8+56], rax // compare result of c->Get() and aMinimum
cmovl rax, QWORD PTR [r8+56] // if it's less then aMinimum = result of c->Get()
add rdx, 8 // next vector element
cmp rdx, rcx // end of the vector?
jne SHORT $LL21@GetMinimum
$LN36@GetMinimum:
fatret 0 // beautiful friend, the end
コンパイラが の値を読み取ってc->Get()と比較しaMinimum、条件付きで の RE-READ 値を に移動してc->Get()も問題ないと判断する方法がわかりませんaMinimum。私の考えでは、この値はcmpとcmovl命令の間で変更された可能性があります。私が正しければ、次のシナリオが可能です。
aMinimum現在は 2 に設定されていますc->Get()1 を返しますこれ
cmpが完了し、less-thanフラグが設定されます別のスレッドが、現在のスレッドが現在保持している値
cを 3 に更新します。cmovlaMinimum3に設定プロデューサは 3 を認識し、リングバッファの位置 2 のデータがまだ処理されていなくても上書きします。
私はあまりにも長い間それを見てきましたか?次のようなものではないでしょうか。
mov rbx, QWORD PTR [r8+56]
cmp rbx, rax
cmovl rax, rbx