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 に更新します。cmovl
aMinimum
3に設定プロデューサは 3 を認識し、リングバッファの位置 2 のデータがまだ処理されていなくても上書きします。
私はあまりにも長い間それを見てきましたか?次のようなものではないでしょうか。
mov rbx, QWORD PTR [r8+56]
cmp rbx, rax
cmovl rax, rbx