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

增量在x86中是一个整数原子吗?[副本]

王波
2023-03-14

在多核x86机器上,假设在core1上执行的线程增加一个整数变量a,同时Core2上的线程也增加它。假设a的初始值为0,那么它最终是否总是2?或者它还有其他价值?假设a被声明为volatile,并且我们没有使用原子变量(例如原子变量)

如果在这种情况下a的值实际上总是2,这是否意味着x86-64中的long int也将具有相同的属性,即a最终总是2?

共有3个答案

魏彦
2023-03-14

因为没有人回答你真正的问题,而是告诉你如何以一种总是有效的方式去做:

线程1加载0的值

线程2加载0的值

线程1增加一个存储1

线程2递增其值的本地寄存器副本并存储1。

您可以看到结果为1,而不是结果为2。最后不一定总是2。

单勇
2023-03-14

这里有一个证明,它在特定的实现(gcc)中不是原子的,正如你所看到的(?),gcc生成代码

  1. 将值从内存加载到寄存器

这远远不是原子的。

$ cat t.c
volatile int a;

void func(void)
{
    a++;
}
[19:51:52 0 ~] $ gcc -O2 -c t.c
[19:51:55 0 ~] $ objdump -d t.o

t.o:     file format elf32-i386


Disassembly of section .text:

00000000 <func>:
   0:   a1 00 00 00 00          mov    0x0,%eax
   5:   83 c0 01                add    $0x1,%eax
   8:   a3 00 00 00 00          mov    %eax,0x0
   d:   c3                      ret

不要被mov指令中的0x0所愚弄,那里有4个字节的空间,链接器将在链接此对象文件时填充a的结果内存地址。

谷梁楷
2023-03-14

X86上的增量内存机器指令只有在使用LOCK前缀时才是原子的。

C和C中的X没有原子行为。如果您解锁增量,由于处理器正在读取和写入X的竞赛,如果两个单独的处理器尝试增量,您可能最终只能看到一个增量或两个增量(第二个处理器可能已经读取了初始值,将其增量,然后在第一个写回结果后写回)。

我相信C 11提供了原子增量,大多数供应商编译器都有一种惯用的方法来导致某些内置整数类型(通常是int和long)的原子增量;请参阅编译器参考手册。

如果您想增加一个“大值”(例如,一个多精度整数),您需要使用一些标准的锁定机制,如信号量。

请注意,您还需要担心原子读取。在x86上,如果32位或64位值是64位字对齐的,则读取该值恰好是原子的。对于“大价值”来说,情况并非如此;同样,您需要一些标准锁。

 类似资料:
  • 问题内容: 我是否必须退还该物体然后放入新物体?还是我可以直接增加? 没有办法做到这一点(这行不通): 问题答案: 我是否必须退还该物体然后放入新物体? 只要使用包装器类,就可以,因为它是不可变的。您可以改用可变包装器类,即使是具有方法的包装器类。但是,您将失去对值使用自动装箱和自动拆箱的功能。

  • 问题内容: 我正在尝试以原子方式在Django中增加一个简单的计数器。我的代码如下所示: 如果我正确理解Django,则应将函数包装在事务中并使增量成为原子。但这不起作用,并且计数器更新中存在竞争条件。如何使此代码成为线程安全的? 问题答案: Django 1.1的新功能 或使用F表达式: 请记住指定要更新的字段,否则您可能在模型的其他可能字段上遇到竞争条件!

  • 问题内容: 我正在创建一个网站,希望在其中添加标准MyISAM表中的计数器。 简化示例: 如果多个连接都在执行相同的查询,这会引起问题吗,还是MySQL会照顾它并锁定表或其他东西以确保没有冲突? 问题答案: MyISAM表使用表级别锁定。这意味着在执行更新查询期间,整个表将被锁定。因此,简化用例的答案是:是的,这是线程安全的。但是,如果您使用其他存储引擎,或者您的更新中包含多个表,则情况可能并非如

  • 问题内容: 在Objective-C中,您可以区分原子性质和非原子性质: 根据我的理解,您可以安全地从多个线程读取和写入定义为原子的属性,而同时从多个线程中写入和访问非原子属性或ivars可能导致不确定的行为,包括严重的访问错误。 因此,如果您在Swift中有这样的变量: 我可以安全地并行读写该变量吗?(不考虑这样做的实际含义)。 问题答案: 假设尚无底层文档,这还为时尚早,但是您可以从汇编中学习

  • 问题内容: 如果长变量声明为:- 私有易失性长计数器= 0; 现在,如果我使用预增量运算符对其进行增量,那么该操作将是原子的吗? 如果是,那么它将比对象的增量效率更高吗? 问题答案: 关键字只能解决可见性问题。您必须使用或方法/块来实现原子性(并发编程中的原子性)。 今天又发表了一篇文章:演示何时需要挥发物

  • 我读过,x86的INC指令不是原子指令。我的问题是为什么会这样?假设我们在x86-64上递增一个64位整数,我们可以用一条指令来递增,因为INC指令同时处理内存变量和寄存器。那么为什么它不是原子的呢?