当前位置: 首页 > 知识库问答 >
问题:

我可以直接对原子变量执行算术运算吗?

毕魁
2023-03-14

我可以直接对原子变量执行算术运算吗?

因为我发现C标准库提供了很多实用函数,比如atomic\u fetch\u add来执行原子变量和非原子变量之间的加法。但是,我很好奇,因为变量是原子的,我能直接对它进行算术运算吗?如以下代码所示:

#include <threads.h>
#include <stdio.h>
#include <stdatomic.h>
atomic_int i = 0;
int run(void* v) {
  i += 100;  // <- is this operaiton thread-safe?
  // atomic_fetch_add(&i, 100);
  printf("%d\n", i);
  return thrd_success;
}
int main(void) {
  thrd_t thread;  
  thrd_create(&thread, run, NULL);
  thrd_join(thread, NULL);
  return 0; 
} 

共有2个答案

闻人伟
2023-03-14

i=10语句保持了i的原子性,因为它被用作左值表达式。来自CPPFerence(粗体矿):

内置的递增和递减运算符以及复合赋值是读-修改-写原子操作,具有完全顺序一致的顺序(就像使用memory_order_seq_cst)。如果需要不太严格的同步语义学,可以使用标准库函数来代替。

链接页面上给出的示例在acnt变量上使用内置(预)增量操作,但它也可以像代码一样使用复合赋值。

然而,更复杂的算术运算可能会导致i变量失去原子性,如果它不被严格用作左值表达式。来自同一页:

原子属性仅对左值表达式有意义。左值到右值转换(对从原子位置读取到CPU寄存器的内存进行建模)将原子性与其他限定符一起剥离。

高宇定
2023-03-14

C2011:引用N1570§6.15.6.2p3中明确允许对原子类型变量进行复合赋值

形式为E1 op=E2的复合赋值等价于简单赋值表达式E1=E1 op(E2),除了左值E1只求值一次,并且对于不确定顺序的函数调用,复合赋值的操作是一次求值。如果E1具有原子类型,则复合赋值是一种具有内存顺序顺序顺序顺序顺序顺序顺序顺序顺序顺序顺序顺序语义的读-修改-写操作。[脚注113]

强调我的。脚注113接着给出了一个具体的例子,说明如何将E1 op=E2翻译成

我相信可以应用于原子类型的其他运算符是postfix--,它们也保证执行原子读-修改-写(§6.5.2.4)和简单赋值,这是保证的适当地执行原子加载或存储(§6.2.6.1)

注意:前缀--不能保证执行原子读-修改-写(比较6.5.2.4与6.5.3.1)。

我读了6.2.6.1的这句话

原子类型对象的加载和存储使用memory\u order\u seq\u cst语义完成。

这意味着对大多数其他运算符来说,使用原子左值作为操作数是有效的,并且执行原子加载,之后不专门处理该值。不要在这一部分引用我的话。

C可以具有不同的规则。我将把C标准的注释留给其他人。

 类似资料:
  • 问题内容: 我一直在阅读有关Go中的常量的文章,并且试图了解它们如何在内存中存储和使用。您可以在Go中对非常大的常量执行运算,并且只要结果适合内存,就可以将结果强制为类型。例如,如您所料,此代码显示: 这是如何工作的?在某个时候,Go必须存储并存储在内存中,以便对其执行操作。那么常量是如何存储的,Go如何对其进行算术运算呢? 问题答案: 简短摘要(TL; DR)在答案的结尾。 无类型的任意精度常量

  • 问题内容: 我在csv文件中有一个日期列,说有这种格式的日期,我还有另外一列。在列中,我要填充紧接在日期列中提到的日期之后的日期。例如。如果date列具有日期,那么我想在Next_Day列中。 我们可以在excel中使用,但我不知道如何在Python中执行此操作。 请帮助我解决这个问题。 问题答案: 使用

  • 问题内容: 有没有一种方法可以执行以下任一操作: - 要么 - 问题答案: 并非开箱即用。但是,很容易以多种语言(包括JS)进行手工构建。 您可以使用基于ASCII的名称(例如)来避免在不需要时使用字符串。但是,由于有人用字符串表示运算符并希望从中获得功能,所以提出了与此问题类似的问题的一半。

  • 我有一个具有两个数据成员的泛型类。这是我写的一段代码 我想对num1和num2进行简单的算术运算,比如加法和减法,我还想进行简单的二进制运算,比如 但是这是不允许的,那么有人能告诉我如何执行这些任务吗?

  • 本文向大家介绍C#程序执行所有基本算术运算,包括了C#程序执行所有基本算术运算的使用技巧和注意事项,需要的朋友参考一下 C#中的基本算术运算符包括以下内容- 运算符 描述 + 加两个操作数 -- 从第一个减去第二个操作数 * 将两个操作数相乘 / 将分子除以除分子 % 模运算符和整数除后的余数 ++ 增量运算符将整数值增加一 - 减法运算符将整数值减一 要添加,请使用加法运算符- 同样,它适用于减

  • 我想执行基本的算术运算,如加法,减法,乘法和除法,每个操作仅使用一个通用方法,用于包装类型,如,,...(不包括和)。 我尝试使用泛型类做如下(用于添加)。 它会发出编译时错误, 运算符不能应用于E,E 有没有办法使用这种通用版本来实现这种操作?