OS / Linux / pthread_cond_wait 为什么需要传递 mutex 参数?

栗子:

mutex.lock();

while (判断“条件”是否成立) {
    pthread_cond_wait 等待
}

mutext.unlock();

条件变量这个互斥锁,不是用来保护条件变量的内部状态。而是用来保护外部“条件”(就是那个 while 循环中的判断)。假如条件变量的内部状态需要锁定,完全可以在内部实现中维护一个锁,没有必要从外部传进来。

用于判断是否等待的“条件”,通常就是线程之间共享的某个变量值。A 线程判断“条件”等待,会读取共享变量。B 线程让“条件”满足,会修改变量。这个锁,就是保护线程间的共享变量(“条件”),让“条件”不会一边修改,一边读取。

这把锁还有个额外的作用。wait 函数会阻塞,将线程 A 放到阻塞队列中。wait 函数放在锁的 lock,unlock 内部,也保证了线程还没有真正放到阻塞队列时,线程 B 不能修改“条件”后进行唤醒。这段话应该暂时读不懂,可回头再看,先放在这里,不然描述就不够准确。

不同的应用会有不同的“条件”,在实现条件变量这个库时,是没有办法预先知道这个“条件”究竟是什么。因此要保护“条件”,就只能让用户自己在库外部分配锁。

弄清了这个互斥锁究竟在保护什么。这时我们才能进一步讨论 pthread_cond_wait 为什么要传入这个锁呢?这点就跟 wait 的实现有关。

先来看等待线程 A 的写法。

mutex.lock();

while (判断“条件”是否成立) {
    pthread_cond_wait 等待
}

mutext.unlock();

判断“条件”是否成立,在 lock, unlock 之间受到保护。pthread_cond_wait 可能会阻塞,假如真的阻塞,mutex 这锁就一直不能被释放了。因此在 pthread_cond_wait 的实现内部,在阻塞之前,必须先将锁释放。在唤醒的时候,再重新获取锁。

pthread_cond_wait 展开,内部实现中,会有下面的过程。

做一些其它事情
mutext.unlock()
阻塞中...
唤醒
mutext.lock()

假如在线程 A 中完全展开 pthread_cond_wait

mutex.lock();

while (判断“条件”是否成立) {
    做一些其它事情
    mutext.unlock()
    阻塞
    唤醒
    mutext.lock()
}

mutext.unlock();

可以看到,判断“条件” 一直在 mutext 的 lock, unlock 之间,受到保护。

来到这里,我们总结一下。

  1. 跟条件变量关联的互斥锁,是用于保护判断“条件”,并非条件变量的内部状态。
  2. 将互斥锁,传入 wait 的实现中,是让条件变量库可以在适当的时机释放(unlock)和重新获取(lock)这把锁。

注意上面第 2 点中,“适当时机”这个词。假如不将这个锁传入 pthread_cond_wait,让用户自己在阻塞前先释放锁,是没有办法做到适当时机的。阻塞队列在条件变量库内部维护,只有条件变量库内部才能控制这个时机。

wait 会阻塞,将线程 A 放到阻塞队列中。在线程还没有真正放到阻塞队列时,需要一直上锁。不然另一线程 B 修改“条件”后进行唤醒,这个线程 A 还没有在阻塞队列中,就不能被唤醒了。因而这把保护外部判断“条件”的锁,需要传入到 wait 函数中。等将线程真正放到阻塞队列后才能解锁,之后线程被唤醒后再重新获取。

线程 A 的 pthread_cond_wait 需要传入 mutext,并且 pthread_cond_wait 一定要在 lock 和 unlock 之间。

至于线程 B, 用于修改“条件”。修改“条件” 也必须在 lock 和 unlock 之间,受互斥锁保护。至于 pthread_cond_signal 是否在 lock 和 unlock 之间,其实是没有关系的。但 pthread_cond_signal 必须在修改“条件”之后,不然可能 A 线程被唤醒后,条件不满足继续等待,这个唤醒信号就丢失了。

mutext.lock()
修改”条件“
pthread_cond_signal 唤醒
mutext.unlock()

也可以将 pthread_cond_signal 移到 unlock 外部。

mutext.lock()
修改”条件“
mutext.unlock()
pthread_cond_signal 唤醒

条件变量等待时,那个 wait 的判断,需要使用 while 循环,而不是 if,是防止虚假唤醒。就不再一一分析了。

 

作者:黄兢成
链接:https://www.zhihu.com/question/24116967/answer/676751734
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

 

(SAW:Game Over!)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值