0%

C++并发编程-锁、互斥量、原子操作的区别与联系

2020年3月17日 下午5:05

互斥量

互斥量的基本语义是,一个互斥量只能被一个线程锁定,用来保护某个代码块在同一时间只能被一个线程执行。

在阅读的时候,我心里也有前面几个读者的关于锁、互斥量、原子操作的区别与联系的疑问🤔。

我尝试说一下我的理解:站在需求的角度

  1. 对单独没有逻辑联系的变量,直接使用原子量的relaxed就够了,没必要加上内存序
  2. 对于有联系的多个多线程中的变量,这时就需要考虑使用原子量的内存序
  3. 对于代码段的保护,由于原子量没有阻塞,所以必须使用互斥量和锁来解决
    Ps:互斥量+锁的操作 可取代 原子量。反之不可。

另外,还产生新的疑问:

  1. 互斥量的定义中,一个互斥量只允许在多线程中加一把锁,那么是否可以说互斥量只有和锁配合达到保护代码段的作用,互斥量还有其他单独的用法吗?
  2. 更近一步,原子量+锁,是否可以完成对代码段的保护?而吴老师也在评论区里提到:锁是由原子量构成的。

作者回复:

  • 你从需求方面理解的 1、2、3 我觉得都对,很好!
  • “互斥量只有和锁配合”这个提法我觉得很怪:互斥量是个对象,(加/解)锁是互斥量支持的动作——如果你指 lock_guard 之类的类,那是辅助的 RAII 对象,目的只是自动化互斥量上的对应操作而已。
  • 你可能是被“操作系统中锁的实现原理”这样的提法带偏了。没有作为名字的专门锁对象,只有互斥量、条件变量、原子量。我也被带偏了,我在某个评论里说“锁”的时候,指的就是互斥量加锁

作者回复:

  1. “可见”,可以理解成获得和释放操作的两个线程能观察到相同的内存修改结果。
  2. 原则上任何多线程访问的变量应该要么是原子量,要么有互斥量来保护,这样最安全。特别要考虑内存序的,当然就是有多个有逻辑相关性的共享变量了。对于单个的变量,比如检查线程是否应该退出的布尔变量,只要消除了编译器优化,不需要保证访问顺序也可以正常工作;这样原子量可以使用 relaxed 的访问方式。