原子操作与并发安全

一直以来,都对原子操作和并发安全都有些误解,认为一个操作不是原子的,那它就不是并发安全的,这样以来,就迟疑了,这么说来:
C语言一个简单的赋值语句也不是原子的咯? a = b是否是原子操作? 见代码如下:
int main() {
    int a = 0;
    int b = 2;
    a = b;
}


编译这段代码: g++ -c -g -Wa,-adlhn Assign.c > Assign.asm
可以发现(只显示a = b部分asm码):
movl	-8(%ebp), %eax
movl	%eax, -4(%ebp)

大家看,它由两条汇编指令完成操作,简单解释一下:
  • a ==> -4(%ebp)
  • b ==> -8(%ebp)
  • movl与mov参数顺序相反,movl SRC, DEST
  • movl -8(%ebp), %eax ==> movl b, %eax (先将寄存器%eax赋值为b的值)
  • movl %eax, -4(%ebp) ==> movl %eax, a (将a的值赋值为寄存器%eax的值)

经过这两个指令,最终实现了a = b的赋值

所以,似乎我可以负责任的说,a = b不是原子的。

好吧,既然它不是原子的,那它又是否是并发安全的呢?当然,上面这个例子似乎与并发没多大关系,那就定义这样一个类吧:
class CObject {
private:
    int _v;
public:
    CObject() { _v = 0; }
    void putValue(int v) { _v = v; }
    int  getValue() const { return _v; }
};

同样是只看_v = v部分的汇编指令
movl	8(%ebp), %eax
movl	12(%ebp), %edx
movl	%edx, (%eax)

解释如下:
  • 8(%ebp) ==> _v
  • 12(%ebp) ==> v
  • movl 8(%ebp), %eax ==> %eax赋值为_v的地址
  • movl 12(%ebp), %edx ==> %edx赋值为v的地址
  • movl %edx, (%eax) ==> %eax对应地址的值赋值为%edx对应的值

过程其实都一样,无非为了说明,赋值操作不是原子的。

如果是我以前的理解,不是原子操作就不是并发安全的,那并发程序该怎么写阿?

其实只能说,这是我的误解,首先我们要仔细想想,在什么情况下才会产生并发问题:
就我的理解,多个线程竞争共享数据时,才会有并发问题,回过头再来看上面那几行汇编代码,_v属于共享数据,可真正产生竞争只可能在movl %edx, (%eax),这个时候,可能有多个线程想进行这一步操作,事实上这个操作应该算是原子的吧,因此这样的赋值操作就应该是并发安全的。

你可能感兴趣的:(并发)