使用 InterlockedCompareExchange 无锁

发布于 2024-11-05 00:11:24 字数 361 浏览 0 评论 0原文

我正在尝试使用互锁操作使以下代码片段无锁,知道如何翻译吗?

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();
}

这里面有什么问题/种族吗?

I am trying to make following snip of code lockless using interlocked operations, Any idea how to translate this?

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

}

I was thinking something like

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

Is there any issues/race in this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

土豪我们做朋友吧 2024-11-12 00:11:24

从表面上看,这看起来是正确的,但每次连续使用两个互锁操作时,您都会将自己暴露在 ABA 问题。在这种情况下,一个线程无法将其从 0xFFFF 更改为 1(ICX 返回 !=0xFFFF),因此它会继续执行 if 分支并递增它。在运行 InterlockedIncrement 之前,另一个线程将 m_ref 更改回 0xFFFF,并且原始线程递增 0xFFFF。根据 m_ref 的类型/语义,效果会很谨慎,但肯定会很糟糕。

您应该对 0xFFF 到 1 以及 X 到 X+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 ();
}

This looks correct at a superficial glance, but every time you use two interlocked operations in a row you are exposing yourself to the ABA problem. In this case one thread fail to change it from 0xFFFF to 1 (the ICX returns !=0xFFFF) so it goes ahead and takes the if branch and increments it. Before it runs the InterlockedIncrement another threads changes the m_ref back to 0xFFFF and the original thread increments 0xFFFF. Depending on the type/semantics of m_ref the effect will wary, but will surely be bad.

You should do one single ICX operation, for both the 0xFFF to 1 and X to X+1, and always retry if you lost the 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 ();
}
伪装你 2024-11-12 00:11:24

是的,有一场比赛。另一个上下文可以在 InterlockedCompareExchange 和 InterlockedIncrement 之间做很多事情

Yes there's a race. Another context could do a lot in between InterlockedCompareExchange and InterlockedIncrement

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文