5

インターロックされた操作を使用して、次のコードの断片をロックレスにしようとしています。これを変換する方法はありますか?

if (m_Ref == 0xFFFF)
    m_Ref = 1;
else
{
    if (++m_Ref == 1)
        CallSomething(); //

}

私は次のようなことを考えていました

if (InterlockedCompareExchange(&m_Ref, 1, 0xFFFF) != 0xFFFF))
{
    if (InterlockedIncrement(&m_Ref) == 1)
         CallSomething();
}

これに問題/人種はありますか?

4

2 に答える 2

8

これは一見正しいように見えますが、2つのインターロックされた操作を続けて使用するたびに、ABA問題にさらされています。この場合、1つのスレッドが0xFFFFから1への変更に失敗するため(ICXはを返します!=0xFFFF)、先に進んでif分岐を取得し、それをインクリメントします。実行する前に、InterlockedIncrement別のスレッドがm_ref 0xFFFFに戻り、元のスレッドが0xFFFFをインクリメントします。m_refのタイプ/セマンティクスによっては、効果は慎重になりますが、確かに悪いものになります。

0xFFFから1およびXからX+1の両方に対して1つのICX操作を実行し、ICXを失った場合は常に再試行する必要があります。

volatile <type> m_ref;

<type> ref, newRef, icxref;
do
{
   ref = m_ref;
   newRef = (0xFFFF == ref) ? 1 : ++ref;
   icxref = InterlockedCompareExchange (&m_ref, newRef, ref);
} while (icxref != ref);
if (newRef == 1 && ref != 0xFFFF)
{
   DoSomething ();
}
于 2011-05-02T22:53:27.023 に答える
4

はい、レースがあります。別のコンテキストはInterlockedCompareExchangeInterlockedIncrement

于 2011-05-02T22:42:18.733 に答える