InterlockedCompareExchange - 确切的对齐要求是啥以及如何执行?
Posted
技术标签:
【中文标题】InterlockedCompareExchange - 确切的对齐要求是啥以及如何执行?【英文标题】:InterlockedCompareExchange - what are the exact alignment requirements and how can they be enforced?InterlockedCompareExchange - 确切的对齐要求是什么以及如何执行? 【发布时间】:2016-02-12 16:51:11 【问题描述】:我无法理解 MSDN 文档对 Interlocked Variable Access 系列函数的含义。 我使用InterlockedExchange 进行设置,InterlockedCompareExchange 用于获取多个线程使用的成员变量。
该成员在一个 1 字节的打包类中:
#pragma pack(1)
class MyClass
char _;
long m_MyMember;
// ...
所以成员是由设置的
InterlockedExchange(&m_MyMember, 1);
得到了
long value = InterlockedCompareExchange(&m_MyMember, 0, 0);
InterlockedExchange 文档没有以任何方式提及对齐 (Strg+F "align"),但 InterlockedCompareExchange 确实:
此函数的参数必须在 32 位边界上对齐;否则,该函数将在多处理器 x86 系统和任何非 x86 系统上运行不可预测。
但是,据我了解,参数都是堆栈变量,因为可以重写上面的调用
long *ptr = &m_MyMember;
long zero = 0;
long value = InterlockedCompareExchange(ptr, zero, zero);
所以我们有块本地自动存储类变量。无论 m_MyMember 所在的类如何,所有 4 字节都完美对齐。 当然,我认为这是错误的,这意味着 ptr 后面的地址必须在 4 字节边界上对齐。
所以我的问题是:
-
InterlockedExchange 是否真的与对齐无关,或者这是文档中的漏洞?
您能否确认不是字面意义上的参数,而是 long* 后面的地址必须是 4 字节对齐的(我不能假设其他参数为什么不能是 4 字节对齐,因为它们是堆栈变量)?
如果对 2 的回答是是:如何解决?更改周围类的对齐方式不是一种选择,c++ 11 atomic 或 boost 也不是(所有这些都是由于公司限制和 msvc10 到 msvc14 所需的可编译性)。
我考虑过声明 m_MyMember volatile 并使用临界区来访问它。虽然我希望更好地正确声明 m_MyMember 以根据需要对齐,因为这些互锁变量访问函数都围绕给定的代码库,我不想为每个变量添加额外的伴随 CS .
【问题讨论】:
为什么-哦-你为什么要这样做?在 x86 和 x64 上,InterlockedExchange() 生成 XCHG 指令,它始终是原子的。未对齐变量的成本是您必须自己衡量的,我猜是胳膊和腿。 您声称,由于参数在堆栈上,因此记录的合同得到满足……这是对所使用的语言的吹毛求疵。显然,文档意味着指针必须对齐。没有办法让自己脱离合同! @Hans Passant:由于我必须使用遗留接口。同样,这不是衡量的主题,而是符合规范的代码。我已经在 SO 的其他地方阅读了生成的指令(以及硬件异常,请参阅 csgordons 对***.com/questions/881820/… 的评论),但我缺乏评估这些陈述的洞察力。 @usr:是的,这也是我的假设。在 MSDN 的那个关键地方使用这种松散的措辞真的很烦人。 【参考方案1】:真正的限制不是微软的,而是硬件。为了原子地改变东西,它必须对齐(指针)。
对于临界区或 STD::atomic 的成员也是如此
在不重新对齐类的情况下,如果您可以使用 interlock
变量来保证与类的 4 字节对齐,那么这应该可以工作
【讨论】:
我的意思是我会使用临界区来保证唯一的所有权,然后读写 volatile 变量的内容。或者您所说的“关键部分的成员”是什么意思?对不起,我不明白你的最后一句话:“如果不重新对齐类,如果你可以使用联锁变量来保证与类的 4 字节对齐,那么应该可以”以上是关于InterlockedCompareExchange - 确切的对齐要求是啥以及如何执行?的主要内容,如果未能解决你的问题,请参考以下文章