Ira*_*ter 28
只有在使用LOCK前缀时,X86上的increment-memory机器指令才是原子的.
C和C++中的x ++没有原子行为.如果您执行解锁增量,由于处理器正在读取和写入X的比赛,如果两个单独的处理器尝试增加,您最终只能看到一个增量或两者都被看到(第二个处理器可能已经读取了初始值,增加了它,并在第一次写回结果后写回来).
我相信C++ 11提供原子增量,并且大多数供应商编译器都有惯用的方法来导致某些内置整数类型(通常是int和long)的原子增量; 请参阅编译器参考手册.
如果要增加"大值"(例如,多精度整数),则需要使用一些标准锁定机制(如信号量).
请注意,您还需要担心原子读取.在x86上,如果是64位字对齐,则读取32位或64位值恰好是原子的.对于"大价值"而言,情况并非如此; 再次,你需要一些标准锁.
这是一个证明它在特定实现(gcc)中不是原子的,如你所见(?),gcc生成的代码
这离原子还很远.
$ 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
Run Code Online (Sandbox Code Playgroud)
不要被被愚弄0x0的mov指令,有足够的空间用于4个字节那里,链接器将在最终的存储器地址填写a在这个目标文件被链接在那里.
因为没有人回答你的实际问题,而是以一种始终有效的方式向你展示如何做到这一点:
线程1加载值0
线程2加载值0
线程1递增商店1
线程2递增其本地寄存器值的值并存储1.
正如您所看到的,最终结果是一个等于1而不是2的值.最后它不会总是2.
这不保证.您可以使用该lock xadd指令来实现相同的效果,或使用C++ std::atomic,或使用#pragma omp atomic或编写的任何其他并发解决方案,以避免重新发明轮子的麻烦.
| 归档时间: |
|
| 查看次数: |
18409 次 |
| 最近记录: |