如何将非原子操作转换为原子操作

时间:2011-07-10 07:24:03

标签: c operating-system atomicity

我正在尝试理解原子和非原子操作。关于操作系统以及关于C. 根据维基百科页面here

考虑一个简单的计数器,不同的过程可以增加 非原子

天真的,非原子的实施:
读取内存位置的值;
将值加1;
将新值写回内存位置。

现在,想象两个进程正在运行递增单个共享内存位置:
第一个进程读取内存位置的值;
第一个过程为值添加一个;
但是在它将新值写回内存位置之前它被暂停,并允许第二个进程运行:
第二个进程读取内存位置的值,与第一个进程读取的值相同;
第二个过程为该值添加一个;
第二个进程将新值写入内存位置。

如何将上述操作作为一个大气操作。 我对原子操作的理解是任何不间断执行的东西都是原子的。 例如,

int b=1000;
  b+=1000;

根据我的理解应该是一个原子操作,因为两个指令都是在没有中断的情况下执行的,我从某个人那里学到了在C中没有任何已知的原子操作,因此上述两个语句都是非原子的。 所以我想要理解的是,当涉及到编程语言而不是操作系统时,原子性是什么?

5 个答案:

答案 0 :(得分:4)

C99没有任何方法可以使变量相对于其他线程具有原子性。 C99没有多线程执行的概念。因此,您需要使用特定于编译器的扩展和/或CPU级指令来实现原子性。

下一个C标准,目前称为C1x,将包括原子操作。

即便如此,纯粹的原子性只能保证操作是原子的,它不能保证该操作何时对其他CPU可见。为了实现可见性保证,在C99中,您需要研究CPU的内存模型,并可能使用称为栅栏或内存屏障的特殊CPU指令。您还需要使用某些特定于编译器的编译器屏障告诉编译器。 C1x定义了几个内存排序,当你使用原子操作时,你可以决定使用哪个内存排序。

一些例子:

/* NOT atomic */
b += 1000;

/* GCC-extension, only in newish GCCs 
 *   requirements on b's loads are CPU-specific
 */
__sync_add_and_fetch(&b, 1000);

/* GCC-extension + x86-assembly, 
 *   b should be aligned to its size (natural alignment), 
 *   or loads will not be atomic
 */
__asm__ __volatile__("lock add $1000, %0" : "+r"(b));


/* C1x */
#include <stdatomic.h>
atomic_int b = ATOMIC_INIT(1000);
int r = atomic_fetch_add(&b, 1000) + 1000;

所有这些都看起来很复杂,所以你应该坚持使用互斥体,这会让事情变得更容易。

答案 1 :(得分:3)

int b = 1000;
b+=1000;

在指令级别变成多个语句。至少,准备一个寄存器或存储器,分配1000,然后获取该寄存器/存储器的内容,向内容添加1000,并将新值(2000)重新分配给该寄存器。如果没有锁定,操作系统可以在该操作的任何时刻挂起进程/线程。此外,在多进程系统上,当您的操作正在进行时,不同的处理器可以访问该内存(在这种情况下不会是寄存器)。

当您取消锁定时(这就是如何使其成为原子),您在某种程度上告知操作系统暂停此进程/线程并且不应该访问此内存其他过程。

现在上面的代码可能会被编译器优化为2000到b的内存位置的简单赋值,但是我忽略了这个答案的目的。

答案 2 :(得分:3)

b+=1000在我知道的所有系统上编译为多个指令。因此它不是原子的。

即使b=1000也可以是非原子的,尽管你必须努力构建一个不是原子的情况。

事实上,C没有线程概念,所以在C中没有什么是原子的。你需要依赖编译器和工具的特定于实现的细节。

答案 3 :(得分:0)

上面的语句是非原子的,因为它成为一个移动指令,将b加载到寄存器中(如果它不是),然后向它添加1000并将存储重新加入内存。许多指令集允许原子性通过原子增量最简单的x86与lock addl dest,src;其他一些指令集使用cmpxchg来实现相同的结果。

答案 4 :(得分:0)

  

所以我想要了解的是什么   原子性是不同的   来自编程语言而不是   操作系统?

我对这个问题感到有些困惑。你到底是什么意思?原子性概念在prog中都是相同的。语言和操作系统。

关于原子性和语言,这里有一个关于JAVA中的原子性的链接,可能会给你一个不同的视角:What operations in Java are considered atomic?