使用 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 @ 或 CMPXCHGXCHG (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 编译器?

如何使用 Visual c++ 2008 编译 64 位

Win7 64位无法安装上Microsoft Visual C++ 2010(x86) Redistributable

C++ 程序未在 Visual Studio 2010 中读取绝对路径 [关闭]

Visual Studio 2010 C++:如何判断链接器实际尝试链接的 LIB 文件?