使用托管C++的InterlockedIncrement64函数

6
我正在将使用Visual Studio 2012编写的代码移植到Visual Studio 2015上进行编译。该代码在Windows 2012上可以成功构建。
我遇到了一些调用InterlockedIncrement64的代码问题。对于x64目标,它可以成功构建,但是当目标为Win32且调用代码为托管代码(即使用/clr编译)时,则会失败,出现以下错误:
error C3861: 'InterlockedIncrement64': identifier not found
查看winnt.h文件,似乎在目标为Win32且_MANAGED被定义时,InterlockedIncrement64未定义。
我可以重新排列代码,使得托管代码不会调用InterlockedIncrement64,但我仍然想知道这种行为变化是由Visual Studio 2015引起的原因。

3
你不能只使用托管版本的 System::Threading::Interlocked::Increment(Int64) 吗? - Christian.K
阅读文档网站的第一段:“要操作32位值,请使用InterlockedIncrement函数。”如果您正在处理与Windows相关的任何内容,确实应该阅读文档。其他所有内容都会让您陷入麻烦/无助。这是强制性的。在某些情况下,64位函数可能不会链接/可用于32位目标-在这种情况下始终使用32位函数。 - specializt
头文件中使用内联函数?你这样做是不正确的。确实如此。 - specializt
2
@specializt 你还会把内联函数放在哪里呢?inline关键字的主要用途是允许在头文件中定义函数... - Cody Gray
2
@specializt 不完全是这样。inline关键字的一个含义是提示编译器在每个调用点展开函数。但这基本上是过时的含义。现在,优化器忽略了99%的情况下的提示,因为它们比编写它的程序员更聪明。他们使用启发式算法来决定哪些函数要内联,而不管您是否将它们注释为这样。现在,inline关键字的第二个含义是最重要的,即绕过单一定义规则(ODR),允许函数体出现在头文件中。 - Cody Gray
显示剩余5条评论
1个回答

4
正如其名称所示,InterlockedIncrement64是一个针对LONGLONG的原子增加操作,并且需要内存为64位对齐
鉴于在托管代码中无法设置内存对齐,而且可能用于托管类成员,因此这个限制对我来说很有意义:"...否则,在多处理器x86系统和任何非x86系统上,此函数的行为将变得不可预测。"请思考以下内容:
::InterlockedIncrement64(&_memberVariable);

如果_memberVariable托管世界中分配,那么它不会是64位对齐的(尽管可能偶然发生),并且这段代码在Win32上总是会失败。在定义了_MANAGED时,更简单的方法是删除此函数。 解决方法:检查#ifdef _MANAGED并调用Interlocked::Increment,或者放弃原子性,但在递增后包含内存屏障。

1
我认为一个更好的解决方法是调用专门设计用于此目的的托管 API Interlocked::Increment。您可以获得所有的好处,而没有任何缺点。"入乡随俗..."之类的。 - Cody Gray
1
这是Jitter直接识别的方法之一。变量将在64位模式下对齐,因此x64 Jitter直接生成LOCK XADD指令。但在32位模式下,x86 Jitter会在CLR内部调用一个帮助函数COMInterlocked::ExchangeAdd64()。顺便说一句,这与COM无关。 - Hans Passant
@HansPassant 谢谢,我刚开始写一个测试应用程序来查看生成的汇编代码,但你已经给了我答案!现在我的困惑真的出现了:最终ExchangeAdd64()将调用InterlockedExchangeAdd64,但仍需要64位对齐,而32位Jitter将以32位对齐... - Adriano Repetti
Windows 对 CLR 一窍不通。除非你找到一个双方都关注的人,否则在组织图中移除二十个经理后才能找到它们。而且,这还是在运行时发生的。 - Hans Passant
是的,但如果 InterlockedIncrement64() 在 32 位未对齐时给出不可预测的结果,则 InterlockedExchangeAdd64() 也会如此。好吧,这种情况发生了... - Adriano Repetti
它也可以反过来工作,抖动并不了解Windows的情况。它可以在许多操作系统上运行。语言也不会对操作系统做出任何假设,宏只对C++/CLI有用。由于管道已经存在,宏就没有用处。 - Hans Passant

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接