当前位置:  开发笔记 > 编程语言 > 正文

是否将指针视为C中的原子动作?

如何解决《是否将指针视为C中的原子动作?》经验,为你挑选了3个好方法。

如果我有一个多线程程序通过引用读取缓存类型的内存.我可以通过主线程更改此指针,而不会冒任何其他线程读取意外值的风险.

在我看来,如果更改是原子的,其他线程将读取旧值或更新值; 从不随机内存(或空指针),对吧?

我知道无论如何我应该使用同步方法,但我仍然很好奇.

指针变化是原子的吗?

更新:我的平台是64位Linux(2.6.29),虽然我也想要一个跨平台的答案:)



1> Michael..:

正如其他人所提到的,C语言中没有任何内容可以保证这一点,而且它取决于您的平台.

在大多数现代桌面平台上,对字大小的对齐位置的读/写将是原子的.但由于处理器和编译器对读写的重新排序,这确实无法解决您的问题.

例如,以下代码被破坏:

线程A:

DoWork();
workDone = 1;

线程B:

while(workDone != 0);

ReceiveResultsOfWork();

虽然写入workDone是原子的,但在许多系统上,处理器无法保证workDone在完成通过写入之前,写入对其他处理器DoWork()是可见的.workDone在调用之前,编译器也可以自由地重写命令DoWork().在这两种情况下,ReceiveResultsOfWork()可能会开始处理不完整的数据.

根据您的平台,您可能需要插入内存挡板等,以确保正确的订购.为了做到这一点,这可能非常棘手.

或者只是使用锁.更简单,更容易验证是正确的,并且在大多数情况下足够高性能.


如果编译器可以证明DoWork没有以任何定义的方式访问workDone,那么编译器可以重新排序.如果DoWork足够小并且在相同的翻译单元中并且编译器决定内联它,则实际上可能发生这种情况.
虽然它是一个C++关键字,但大多数C编译器都遵循volatile修饰符,这会阻止编译器重新排序写入变量,并几乎保证内存是通过缓存写入的.我说几乎是因为C中没有任何保证,但它是每个主要C编译器的惯例.
@Don:内存防护不是为防止编译器中的重新排序而设计的,它们旨在防止在CPU中重新排序.

2> Dan Breslau..:

C语言没有说明任何操作是否是原子操作.我曾经研究过8位总线和16位指针的微控制器; 这些系统上的任何指针操作都可能是非原子的.我想我记得英特尔386s(其中一些有16位总线)引起了类似的担忧.同样,我可以想象具有64位CPU但32位数据总线的系统,这可能会引起与非原子指针操作类似的担忧.(我没有检查是否确实存在任何此类系统.)

编辑:迈克尔的回答非常值得一读.总线大小与指针大小不是关于原子性的唯一考虑因素; 这只是我想到的第一个反例.



3> JaredPar..:

你没有提到一个平台.所以我认为会有一个更准确的问题

指针变化是否保证是原子的?

区别是必要的,因为不同的C/C++实现可能会在此行为中有所不同.特定平台可以保证原子分配并且仍然在标准范围内.

至于这是否在C/C++中得到全面保证,答案是否定的.C标准没有这样的保证.保证指针赋值的唯一方法是使用特定于平台的机制来保证赋值的原子性.例如,Win32中的Interlocked方法将提供此保证.

你在做哪个平台?

推荐阅读
郑小蒜9299_941611_G
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有