原子操作(atomic operation)指的是由多步操作组成的一个操作。如果该操作不能原子地执行,则要么执行完所有步骤,要么一步也不执行,不可能只执行所有步骤的一个子集。
    任何要求多于一个函数调用的操作都不是原子操作,因为在两个函数调用之间,内核可能会临时挂起线程,执行其他的操作,当内核切换回当前线程时,之前的数据可能别修改,所以不能保证是原子操作。
    原子操作是不可分割的,在执行完毕之前不会被任何其它任务或事件中断。在单处理器系统(UniProcessor)中,能够在单条指令中完成的操作都可以认为是” 原子操作”,因为中断只能发生于指令之间。
    在C++11之前,C++标准中并没有对原子操作进行规定。如果我们想要实现原子操作,就只能借助汇编语言,或者第三方的线程库(比如pthread来实现)。
    在C++11中,终于有了原子操作的概念。标准提供了多个原子操作数据类型,atomic_int、 atomic_long等。在程序中使用这些数据类型的时候,编译器将保证针对原子数据类型的操作都是原子性的。也就是说,编译器保证多个线程访问这个共享资源的正确性。这样,我们在程序中就可以较少锁的使用,提高程序效率。
    例子:

    1. long count = 0;
    2. void func() {
    3. count++;
    4. }

    如果同时启动10个线程执行func函数,所有线程都执行完成后count的值是多少?
    10,对吗?正确答案是 不确定,从2-10都有可能。
    你没看错,从2-10都有可能,导致这个问题的原因是 count++ 不是一个原子操作,编译成汇编,如下所示:

    1. MOV eax, [count]
    2. INC eax
    3. MOV [count], eax

    在cpu执行时 :
    第一步,先将 count所在内存的值加载到寄存器;
    第二步,将寄存器的值自增1;
    第三步,将寄存器中的值写回内存。
    所以当第一个线程将count值加载到寄存器,并完成自增1,这时寄存器中的值为2,如果此时cpu调度将此线程中断,并执行完其它线程后,再将此线程调度执行,此时,会将2写入到count。count最后的值就成了2!!!
    3-10的结果类似… …
    所以要想保证上面实例的结果正确只需要保证count++ 在执行中不被打断即可。

    1. // 加锁的方式,保证原子操作,比较耗时。
    2. long g_count = 0;
    3. mutex g_mutex;
    4. void func() {
    5. lock_guard<mutex> lock(g_mutex);
    6. count++;
    7. }
    8. // c++11 原子变量,比加锁省时间
    9. #include<atomic>
    10. atomic_long g_count(0);
    11. void func() {
    12. count++;
    13. }