联锁读取 64 位变量

Posted

技术标签:

【中文标题】联锁读取 64 位变量【英文标题】:interlocked reading a 64-bit variable 【发布时间】:2011-10-17 12:59:13 【问题描述】:

我有这个 c++ 代码(VS 2008):

LONGLONG res = InterlockedIncrement64(&m_longlong);

沿着它运行,我希望能够从同一个变量中读取

LONGLONG res = InterlockedWHAT?64(&m_longlong)

由于这是一个 64 位变量,简单的读取不被认为是线程安全的,但我找不到正确的 InterlockedXXX。

我应该如何读取这个变量?

【问题讨论】:

在 64 位架构上,对齐的 64 位读取(QWORD)应该是原子的,IIRC。查看 tr1/boost/c++0x atomic 以获得“无压力”便携式解决方案 谢谢,但我现在不想链接到一个全新的库。寻找 InterlockedXXX 解决方案 评论的想法不是答案 :) 我只是提供想法。如果您知道拱门,您可能只需确保对齐并完成。这个问题受到了限制,这就是为什么这不是一个答案。 @sehe:您不能只读取对齐的QWORD。为了使并发安全,您需要两件事,原子性和写/读顺序。即使 64 位 cpu 会以原子方式读取值,优化器或 CPU 也可能会以意想不到的方式干扰读取。 【参考方案1】:
LONGLONG res = InterlockedCompareExchange64(&m_longlong, 0, 0);

【讨论】:

@user991339 - 另一个线程可以在读取该值以作为第二个参数推送堆栈时修改该值。返回值可以,但共享变量会包含垃圾。 InterlockedExchange64 不好。您必须将其称为InterlockedExchange64(&val, val),现在您应该看到问题所在了。你如何读取val 的值作为第二个参数传递?这与您开始时遇到的问题相同。 @Henrik - InterlockedCompareExchange 也可能发生这种情况,当 m_longlong == 0 和 0 被推入堆栈而另一个线程写入其他值时,不是吗? 不,它不能。如果 m_longlong == 0m_longlong 将设置为 0(即没有更改),否则 m_longlong 将不会被修改。换句话说,这个答案中的代码不能修改m_longlong 你应该选择一个m_longlong 不可能有的值,以避免弄脏缓存行。【参考方案2】:

您可以使用InterlockedOr64 并将零作为第二个参数传递。据我所知,这对 Vista 没有要求,大概是因为它是用编译器内在函数实现的。

【讨论】:

请注意,这会修改值(将结果写回,即使它在数值上相同),这可能会导致性能问题,因为它会弄脏缓存行。 @Raymond 谢谢你的补充。您对这个问题的首选解决方案是什么? 我会使用不太可能的值的InterlockedCompareExchange。 blogs.msdn.com/10152296.aspx【参考方案3】:
LONGLONG res = InterlockedOr64(&m_longlong, 0);

如果您的程序仅在 64 位上运行,您可以简单地读取该值。 MSDN states that

对正确对齐的 64 位变量的简单读写在 64 位 Windows 上是原子操作。

【讨论】:

【参考方案4】:

在 VS 2019 中,您应该使用 __iso_volatile_load64,这是普通负载,因此它比 InterlockedCompareExchange64 更高效

【讨论】:

以上是关于联锁读取 64 位变量的主要内容,如果未能解决你的问题,请参考以下文章

WaitForSingleObject 与联锁*

32 位系统中的 64 位可变读取顺序(低和高)

上传图片获取base64位编码

win7的64位机已经安装了32位jdk,还能不能再安装64位jdk?

64位汇编第二讲——64位汇编中局部变量使用及抬栈方法29171230

在 32 位机器中存储临时 64 位变量