作者:有风吹过best | 2023-08-14 23:52
在C中,是i+=1;
原子?
1> Steve Jessop..:
C标准没有定义它是否是原子的.
在实践中,你永远不会写代码,如果给定的操作,其失败是原子,但你可能会写代码失败,如果它不是.所以假设它不是.
确实如此.但问题"它是原子的"的答案是"否",而问题的答案"它是非原子的"也是"不".而不是像一个不可思议的神谕那样试图欺骗歹徒误解问题的答案,而不是严格要求的问题.这不是一个智力竞赛节目或敌对的交叉询问,我要求有权给予更多的是/否答案;-)
这个答案比现在正在进行投票的人更有意义(来自M. Fernandes)
同意,虽然我开始经验法则"i + = 1;" 对于可移植性来说不是原子的.
要添加的一件事:有特定于平台的函数用于执行原子增量.在Windows下,查看Interlocked功能.
2> DevSolar..:
没有.
C语言标准保证唯一的原子操作是从类型的变量中分配或检索值sig_atomic_t
,定义于
.
(C99,第7.14章信号处理.)
@ Steve:不,在C中,**增量不是原子**.如果需要原子操作,请使用平台的相应API.依赖于实现定义的行为(可能随编译器选项或版本而改变而不另行通知)是通向痛苦的道路."C语言的这种柏拉图式理想"的价值在于,当您的同事在不同的计算机上编译时,您的代码不会随意中断.去过那里,做了大约十年.
@ jldupont:绝对正确.问题是操作是否是C*语言中的原子*,而不是特定的平台/编译器设置.*language*声明原子性声明的唯一地方是`sig_atomic_t`,所以你必须假设任何其他操作都不是原子的安全方面.
说橡胶鸡"不会"下雨是不对的.他们可能会,也可能不会.你不能依赖他们下雨,你不能依赖他们不下雨,所以说他们不会下雨是非常误导的.(就标准而言具有误导性.显然,你可以根据你对C实现的了解做出精明的预测,但这是一个完全不同的陈述).如果有人看到我说,"C中的整数可能是1的补码",并编写依赖它们的代码,那么我认为这显然是他们的错误.他们应该阅读RFC 2119.
+1:最好的答案,当然.这里的每个人都在吸烟,或其他什么.问题是关于C(不是增量在*某些*架构上的某些*实现中是否是原子的).你是正确的DevSolar,答案是否定的!在C中它不是*原子的.如果它恰好在某个平台上编译成原子操作,那不是因为C标准这样做了,这是因为实现了.
是的,在这种情况下"它不是原子的"效果很好,因为正如我在另一个评论中所说的那样,没有人会错误地依赖的非原子事物的行为.我不喜欢的一般是将关于C中发生的事情的陈述分为"真"和"假",因为存在如此大的"未指定"的中间立场.如果有人想要删除硬盘驱动器,那么对于他们来说,未定义的行为是否意味着他们的硬盘驱动器"将"被删除,或者"可能"被执行者自行决定删除.
请注意,C99标准仅保证在异步信号处理程序中只能写入`sig_stomic_t`对象(以明确定义的方式).没有定义从异步信号处理程序中的`sig_atomic_t`对象读取.所以`i + = 1`无论如何都不会在这个特定的情况下很好地定义(尽管`i = 1`将是).
记录在案,我对你的回答没有问题.我只是喜欢提出橡皮鸡的话题;)
3> DigitalRoss..:
用C定义,没有.在实践中,也许吧.把它写在汇编中.
标准不保证.
因此,便携式程序不会做出假设.目前尚不清楚你的意思是"必须是原子的",还是"在我的C代码中恰好是原子的",而第二个问题的答案是它取决于很多事情:
并非所有机器都具有增量存储器操作.有些需要加载和存储值以便对其进行操作,因此答案是"从不".
在具有增量内存op的机器上,无法保证编译器无论如何都不会输出加载,增量和存储序列,或者使用其他非原子指令.
在具有增量存储器操作的机器上,相对于其他CPU单元,它可能是原子的,也可能不是原子的.
在具有原子增量存储器操作的机器上,它可能不被指定为体系结构的一部分,而只是CPU芯片的特定版本的属性,或者甚至仅仅是某些核心逻辑或主板设计的属性.
至于"我如何原子地做这个",通常有一种方法可以快速做到这一点,而不是诉诸(更昂贵)协商的互斥.有时,这涉及特殊的碰撞检测可重复代码序列.最好在汇编语言模块中实现这些,因为它无论如何都是特定于目标的,因此HLL没有可移植性优势.
最后,因为不需要(昂贵的)协商互斥的原子操作是快速且因此有用的,并且在任何情况下需要便携式代码,系统通常具有通常以汇编语言编写的库,其已经实现了类似的功能.