关于条件变量和互斥锁为何配合使用的思考

  • A+
所属分类:网站技术

最近在阅读《现代操作系统》,看到条件变量部分时非常疑惑条件变量为什么需要互斥锁,,查阅了一些资料,进行了一些思考。

我的疑惑点在于条件变量为什么需要有互斥锁的配合,我觉得原因有二。

第一点,首先我们要理解条件变量的作用是在等待某个条件达成时自身要进行睡眠或阻塞,避免忙等待带来的不必要消耗,所以条件变量的作用在于同步。条件变量这个变量其实本身不包含条件信息,条件的判断不在pthread_cond_wait函数功能中,而需要外面进行条件判断。这个条件通常是多个线程或进程的共享变量,这样就很清楚了,对于共享变量很可能产生竞争条件尤其还对共享变量加了条件限制,所以从这个角度看,必须对共享变量加上互斥锁。

第二点,pthread_cond_wait这个函数的过程我们必须了解,首先对互斥锁进行解锁(条件判断不属于函数的功能),解锁之后自身睡眠等待条件达成,注意这时候函数并未返回,因为还缺少一步,待条件完成后重新加锁。pthread_cond_wait提供的重要功能是保证这两个操作一定是原子操作不可分割。试想一下,如果进程A调用了pthread_cond_wait,先进行了解锁,这时候由于进程A时间片到期,轮换到进程B,进程B一直想要这把锁,现在终于拿到了,它干完了事情,调用pthread_cond_signal想唤醒A但是A并未完成睡眠等待条件达成,所以这个唤醒信号就丢失了。

其实第二点并不算是需要配合互斥锁的原因,而是因为有了互斥锁而提供的一个关键功能。但是从另一个角度看,条件变量和互斥锁的配合使非常紧密的。

关于条件变量和互斥锁为何配合使用的思考

还有一个值得思考的地方是,pthread_cond_wait函数最后一步要进行重新加锁,这时候就要求另一个线程将条件达成之时必须解锁。而pthread_cond_signal这个函数的流程是发送信号后本线程立刻阻塞,而等待条件的线程立刻被唤醒。这就可能造成一些问题。

这里另一个线程调用pthread_cond_signal有两种写法:

1、写在互斥锁操作之间:

  1. pthread_mutex_lock
  2. //其他语句
  3. pthread_cond_signal
  4. pthread_mutex_unlock

缺点:在某些线程的实现中,会造成等待线程从内核中唤醒(由于cond_signal)然后又回到内核空间(因为cond_wait返回后会发现锁并未解开的行为),所以一来一回会有性能的问题。但是在LinuxThreads或者NPTL里面,就不会有这个问题,因为在Linux 线程中,有两个队列,分别是cond_wait队列和mutex_lock队列, cond_signal只是让线程从cond_wait队列移到mutex_lock队列,而不用返回到用户空间,不会有性能的损耗。

所以在Linux中推荐使用这种模式。

 

2、写在互斥锁操作之后:

  1. pthread_mutex_lock
  2. //一些语句
  3. pthread_mutex_unlock
  4. pthread_cond_signal

优点:不会出现之前说的那个潜在的性能损耗,因为在signal之前就已经释放锁了

缺点:如果unlock之后signal之前,发生进程交换,另一个进程(不是等待条件的进程)拿到这把梦寐以求的锁后加锁操作,那么等最终切换到等待条件的线程时锁被别人拿去还没归还,只能继续等待。而这在上面的放中间的模式下是不会出现的。

  • 我的微信
  • 这是我的微信扫一扫
  • weinxin
  • 我的微信公众号
  • 我的微信公众号扫一扫
  • weinxin

发表评论

您必须才能发表评论!