condition_variable的使用以及与锁的关系

条件变量和互斥锁是多线程的同步和互斥最基础的两种工具,其中互斥锁使用和功能都比较简单,条件变量在使用和理解起来相对就比较困难,不少初学者对于wait函数必须结合一个锁来使用的原则感到困惑,其实官方指导中已经有详尽的解释和案例,但讲的比较简洁,这里从wait函数执行流程来看下条件变量的使用方法和原理。

正确使用流程
thread1:

locker.lock()							---1
cv.wait(locker,pred)

wait函数展开如下:

while(!pred())							---2         
	等待signal,并调用locker.unlock()		---3
	接受signal返回并调用locker.lock()		---4

thread2:

locker.lock()							---5
change pred								---6
cv.signal()								---7
locker.unlock()							---8

从以上流程来看,无论thread1还是thread2先启动,都能实现想要的效果,先看看假设thread1先启动,执行流程:1,2,3,此时thread1进入block状态等待signal,thread2无论在1,2,3的哪一步启动,启动后执行流程都是5,6,7,8,然后thread1执行4,然后进行下一轮循环,判定条件成功,跳出循环,进入下一步。
再看看假设thread2先启动,执行流程为:5,6,7,8,此时无乱thread1在哪一步启动,执行顺序都为1,2,thread1在进行第一轮条件判断时直接跳过等待进入下一步。

去掉锁的使用流程
那么假设没有加锁会发生什么:
thread1:

cv.wait(locker,pred)

wait函数展开如下:

while(!pred())					---1         
	wait(),blocked				---2
	wait()返回					---3

thread2:

change pred						---4
cv.signal()						---5

直观上来看,很显然,首先pred并不能保证线程安全,当两个线程同时访问这个资源时可能发生不可预料的结果,即使没有发生,来看看假设两个线程以这样的步骤来执行:1,4,5,2,即使thread2已经改变了pred且发出了signal,但由于thread1此时还未处于等待状态,此signal将被忽略。

总结
从上面的整个流程对比来看,可以看出加锁主要有两方面的作用:

  1. 保护pred资源,避免多线程同时读写该资源
  2. 保证等待线程中pred的读操作和wait操作的原子性

你可能感兴趣的:(编程学习)