联锁读取 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 atomicQWORD
。为了使并发安全,您需要两件事,原子性和写/读顺序。即使 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 == 0
则 m_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 位变量的主要内容,如果未能解决你的问题,请参考以下文章
win7的64位机已经安装了32位jdk,还能不能再安装64位jdk?