使用 Visual C++ (2010) 在 64 位版本中生成 CMPXCHG(无 LOCK)
Posted
技术标签:
【中文标题】使用 Visual C++ (2010) 在 64 位版本中生成 CMPXCHG(无 LOCK)【英文标题】:Generating CMPXCHG (without LOCK) in 64-bit builds using Visual C++ (2010) 【发布时间】:2013-01-09 21:09:58 【问题描述】:我需要在同一 CPU 上运行的多个线程的上下文中使用 CAS 函数(假设所有线程都通过SetThreadAffinityMask
静态粘合到选定的 CPU)。
InterlockedCompareExchange
生成 LOCK CMPXCHG。 LOCK 部分会带来一些副作用,例如缓存未命中、总线锁定以及与其他 CPU 争用的可能性,所有这些都很好,但考虑到这种情况,感觉就像是一种奢侈的过度。由于竞争线程在同一个 CPU 上运行,我假设可以删除 LOCK,并且我进一步假设它应该会提高性能。
所以这是我的第一个问题 - 我的假设是否正确?
--
我知道如何使用 32 位版本的内联汇编生成 CMPXCHG。另外,根据this SO thread,我也知道如何处理 64 位版本,但是 作为函数调用。
我不明白,这是我的第二个问题,是如何生成它的内联版本。
--
谢谢。
【问题讨论】:
Hmm.. 如果我正在尝试这个,我会使用宏(OK,~~shudder~~)或 ifdef,这样我以后可以轻松添加锁定前缀,如果我怀疑有问题或发现 SetThreadAffinityMask 是一个理想的“优化”。 因此,如果您有效地保证每个线程都是唯一运行的(因此对共享数据的唯一读写来自单个线程),那么您只是在编写一个单线程程序。那么为什么要使用InterlockedCompareExchange
?
@GManNickG 他在单个逻辑 CPU 上使用多个线程。实际上,他在这里与先发制人的多任务处理作斗争——他需要它是一条指令,这样他的线程就不会在if(x == y) x = z
的中间暂停,但他不需要LOCK
,因为它仍然只在一个单个逻辑 CPU。
@CoryNelson:啊,明白了。所以他想要没有内存栅栏的原子更新。只需要使用平台的实现保证;即撬开MSVC2012的<atomic>
,复制std::atomic<int>::compare_exchange_strong(..., memory_order_relaxed)
。
@CoryNelson - 没有 MSVC2012,所以不能这样做......虽然我怀疑这是另一个内在因素,它不在 2010 版本中。
【参考方案1】:
不是为了回答我自己的问题,而是为了描述一种解决方法。
对于 boolean 变量的 CAS,可以回退到 _bittestandset
,它比 CMPXCHG 慢,但在 VS2010 中具有内在形式。
【讨论】:
【参考方案2】:这个真的是评论多了,不过篇幅有点太有限了……
我怀疑*您会在不使用汇编的情况下自行获得 CMPXCHG
指令。如果该区域非常关键,请使用 Interlocked 内在函数,反汇编输出,删除 LOCK
覆盖前缀并将其链接(我会为 32 位和 64 位变体执行此操作,因为内联 ASM 是 less than optimal in MSVC,因为它的总是被视为不安全,导致插入额外的保护,这可能比调用外部版本更糟糕。从好的方面来说,它也会给你一个更统一的代码布局。
我还建议您对这两种解决方案进行概要分析,不使用 LOCK
,因为大多数较新的 Intel CPU 实施缓存级锁,这大大降低了锁的性能影响(Intel Developer Manual 的第 8 章提供深入了解总线锁定的确切影响)。
*我所说的“怀疑”是指:它不作为显式内在存在,并且使用编译器强制技巧非常很脆弱,并不是说我知道任何强制发射 @987654326 @ 或 CMPXCHG
(XCHG (E)AX,(E)AX
除外,用作对齐 NO-OP)。
【讨论】:
以上是关于使用 Visual C++ (2010) 在 64 位版本中生成 CMPXCHG(无 LOCK)的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Visual C++ 2010 Express 从 32 位环境为 64 位 Windows 编译 Qt?
Visual C++ 2010 Express 是不是包含 x64 编译器?
Win7 64位无法安装上Microsoft Visual C++ 2010(x86) Redistributable