现在的位置: 首页 > 黄专家专栏 > 正文

原子操作浅谈

2014年10月30日 黄专家专栏 ⁄ 共 2170字 ⁄ 字号 评论关闭

秒速赛车公式 www.l19l7.cn 简单说,所谓原子操作是指不会被打断的操作,这种”打断”在操作系统层面,一般是指线程间的上下文切换。假设,一个线程对一个共享的变量写入一个 值,那么另一个观察这个变量的线程,要么看到原值,要么看到新值,不会看到一种中间状态,这种中间状态可以简单理解为部分写入(torn write)。

转到程序设计层面,如果你用C/C++写入或者读取一个变量,这个操作是原子的吗?

答案是:不一定。

假设我们有一个 64bit 的共享变量, store 函数表示写入这个变量一个值

1
2
3
4
uint64 var;
void store() {
  var = 0x1000000000000001;
}

那么 以上的操作,在 32-bit x86 架构上生成的汇编代码可能如下:

1
2
3
mov  DWORD PTR var, 2
mov   DWORD PTR var + 4, 1
ret

明显可以看出,这个赋值操作不是原子的。同样的,我们可以得到读这个 var 的操作也不是原子的。

但是,如果换成 uint32 呢?

1
2
3
4
5
uint32 foo;

void store() {
    foo = 0x80286;
}

如果这个 foo 对其到 32-bit 边界,那么操作是原子的,否则这个操作的原子性某些32-bit的平台不一定支持。 这个在 x64 架构同样成立。我们看下面的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include <iostream>

#pragma pack(2)
struct ShardValue {
  char a[57];
  uint64_t b;
};

char a;
ShardValue var;

void* thread_worker(void* k) {
  uint64_t* v = (uint64_t*)k;
  while (1) {
      var.b = *v; 
  }
}

void* thread_observer(void* k) {
  uint64_t v;
  while(1) {
      v = var.b;
      if (v == 0x1111111100000001 ||
          v == 0x4444444400000001 ||
          v == 0x6666666600000001 ||
          v == 0x2222222200000001 ||
          v == 0x3333333300000001 ||
          v == 0x5555555500000001) {
      } else {
          printf("v : %p\n", v); 
          exit(0);
      }   
  }
}

int main() {
  pthread_t tid_1, tid_2, tid_3, tid_4, tid_5, tid_6;
  uint64_t v1 = 0x1111111100000001;
  uint64_t v2 = 0x2222222200000001;
  uint64_t v3 = 0x3333333300000001;
  uint64_t v4 = 0x4444444400000001;
  uint64_t v5 = 0x5555555500000001;
  uint64_t v6 = 0x6666666600000001;

  pthread_create(&tid_1, NULL, thread_worker, &v1);
  pthread_create(&tid_2, NULL, thread_worker, &v2);
  pthread_create(&tid_3, NULL, thread_worker, &v3);
  pthread_create(&tid_4, NULL, thread_worker, &v4);
  pthread_create(&tid_5, NULL, thread_worker, &v5);
  pthread_create(&tid_6, NULL, thread_worker, &v6);

  pthread_t o1, o2, o3, o4, o5, o6; 
  pthread_create(&o5, NULL, thread_observer, NULL);
  pthread_create(&o6, NULL, thread_observer, NULL);
  pthread_create(&o1, NULL, thread_observer, NULL);
  pthread_create(&o2, NULL, thread_observer, NULL);
  pthread_create(&o3, NULL, thread_observer, NULL);
  pthread_create(&o4, NULL, thread_observer, NULL);

  pthread_join(tid_1, NULL);
  pthread_join(tid_2, NULL);
  pthread_join(tid_3, NULL);
  pthread_join(tid_4, NULL);
  pthread_join(tid_5, NULL);
  pthread_join(tid_6, NULL);
}

测试机是 x86_64 Intel? Core? i5 CPU 760 @ 2.80GHz 4核心

可以得出这样的结果:

v : 0x5555111100000001

查看汇编指令

1
2
3
4
5
6
_Z13thread_workerPv:
......
.L2:
movq  -8(%rbp), %rax
movq  (%rax), %rax
movq  %rax, var+58(%rip)

赋值的汇编指令只有一条,说明在不对齐情况下,最后会生成多条机器指令

抱歉!评论已关闭.

  • 倒着走能治腰颈椎痛?假的! 2019-04-19
  • 长效机制加速推进 楼市下半年或持续降温 2019-04-19
  • 树立文化自信 创新节庆模式 2019-04-19
  • 朝韩将军级会谈时隔11年后在板门店重启 2019-04-19
  • 经济日报多媒体数字报刊 2019-04-18
  • 搞好公有制就是好,故得出结论:计划经济好。 2019-04-18
  • 云南理发店老板涉嫌杀害女演员因办卡纠纷起杀心 2019-04-18
  • 南海网-海南新闻网-权威媒体 海南门户 2019-04-17
  • 海底捞回应侵犯音乐人林海著作权:已停止播放 2019-04-17
  • 自然型社会和规则性社会,是会随着科技的改变而发生改变的,当然只有规矩也就是制度才能规范人的行为,所以国家是不会灭亡的,但国家的形式是会发生改变的。 2019-04-17
  • 惊艳!上外学子英译60首热门中文歌  让世界倾听中国 2019-04-16
  • 西安,给盲人朋友留一条路吧…无障碍设施盲道-编辑整合 2019-04-16
  • 的确如此。报刊亭取消的确是短视行为。把报刊亭设计的现代化一些,与城市绿化衔接起来,相得益彰,成为文化一景多好。 2019-04-16
  • 让更多企业和劳动者尝到协商的“甜头” 2019-04-16
  • 2014金家岭财富论坛嘉宾云集(二) 2019-04-15
  • 472| 792| 350| 686| 563| 130| 142| 848| 477| 646|