Is increment an integer atomic in x86? [duplicate]

本秂侑毒 提交于 2019-11-30 04:52:22

The increment-memory machine instruction on an X86 is atomic only if you use it with a LOCK prefix.

x++ in C and C++ doesn't have atomic behavior. If you do unlocked increments, due to races in which processor is reading and writing X, if two separate processors attempt an increment, you can end up with just one increment or both being seen (the second processor may have read the initial value, incremented it, and written it back after the first writes its results back).

I believe that C++11 offers atomic increments, and most vendor compilers have an idiomatic way to cause an atomic increment of certain built-in integer types (typically int and long); see your compiler reference manual.

If you want to increment a "large value" (say, a multiprecision integer), you need to do so with using some standard locking mechanism such as a semaphore.

Note that you need to worry about atomic reads, too. On the x86, reading a 32 or 64 bit value happens to be atomic if it is 64-bit word aligned. That won't be true of a "large value"; again you'll need some standard lock.

Here's one proof it is not atomic in a particular implementation (gcc), As you can see (?), gcc generates code that

  1. loads the value from memory to a register
  2. increments the content of the register
  3. saves the register back to memory.

That's very far from being atomic.

$ 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

Don't be fooled by the 0x0 in the mov instruction, there's room for 4 bytes there, and the linker will fill in the resulting memory address for a there when this object file is linked.

Since no one has answered your actual question and instead are showing you how to do it in a way that always works:

Thread 1 loads value of 0

Thread 2 loads value of 0

Thread 1 increments an stores 1

Thread 2 increments its local register copy of value and stores 1.

As you can see the end result is a value equal to 1 and not 2. It will not always be 2 at the end.

It’s not guaranteed. You can use the lock xadd instruction to achieve the same effect, or use C++ std::atomic, or use #pragma omp atomic, or any number of other concurrency solutions that have been written to save you the trouble of reinventing the wheel.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!