首页 > 解决方案 > 调用 condition_all() 时,多个线程(正在等待条件变量)如何获取相关锁?

问题描述

从理论上讲,等待线程(比如说 Thread_1)首先获取一个互斥体,然后通过调用 wait() 等待条件变量。对 wait() 的调用会立即解锁互斥锁。当另一个线程(比如说 Thread_2)调用 notify() 时,等待线程 (Thread_1) 被唤醒,并且在 wait(..) 调用返回之前,同一个互斥锁被锁定。

现在假设多个线程在给定时间等待一个条件变量(比如说 Thread_1、Thread_2 和 Thread_3)。现在另一个线程 (Thread_4) 调用 notify_all(),它将通知正在等待条件变量的所有 3 个线程。当他们被唤醒时,他们三个如何才能锁定互斥锁,这应该在 wait(...) 调用返回之前发生?只有一个线程(3 个等待线程中的)可以获取互斥锁。那么 notify_all() 的目的是什么,如果它只能解锁一个线程呢?notify() 和 notify_all() 之间的结果(从等待线程的角度来看)有什么区别?

标签: multithreadingmutexcondition-variable

解决方案


他们三个如何锁定互斥锁?

他们像往常一样一次锁定一个。

一个wait(...)函数可以这样实现:

def wait(cond_var, mutex):
    tricky_internal_wait(cond_var, mutex)
    lock(mutex)

tricky_internal_wait(c,m)函数将自动解锁互斥锁并阻塞与 关联的队列上的调用线程cond_var,但没有理由说明lock(mutex)它末尾的调用需要与普通的lock(mutex).

当在cond_var上面的示例中通知 时,线程将唤醒,然后它会调用lock(mutex),然后如果其他线程已经锁定了互斥锁,操作系统将阻塞与 关联的队列中的调用者mutex。调用者在从wait()调用中返回之前不能从调用中返回lock(),并且lock()在互斥体可用并且调用者获取它之前它不能从调用中返回。就像lock()往常一样。

一个实际的实现可能会更有效地做事情:如果线程已经被其他线程使用,wait(c,m)它可能会将线程直接从cond_var队列移动到mutex队列,而不会唤醒线程。mutex


那么 notify_all() 的目的是什么,如果它只能解锁一个线程呢?

不会只解锁一个。它解锁了所有这些,...

...一次一个。

假设一些线程 T 调用notify_all(cond_var),而线程 X、Y 和 Z 都在等待 中的条件foobar()

def foobar():
    lock(mutex)
    while condition_is_not_satisfied():
        wait(cond_var, mutex)
    do_some_thing_that_requires_condition_to_be_satisfied()
    unlock(mutex)

也许线程 Z 将是第一个从wait()调用中返回的。它会再次检查条件是否真的满足,然后它会做这件事,然后它会解锁mutex并从foobar().

在线程 Z 解锁互斥锁并返回之前,线程 X 和 Y 将无法从wait()调用中返回。

也许在 Z 解锁互斥体之后,从 wait() 返回的下一个将是 X。然后 X 将检查条件是否满足。也许 Z 的动作意味着条件不再满足。在这种情况下,X 将wait()再次调用,并且wait()调用将释放互斥锁。或者,可能条件仍然满足,X 将执行此操作,并显式解锁互斥锁并从foobar().

无论哪种方式,线程 X 将释放互斥锁,然后线程 Y 将能够从wait()调用中返回......

……就这样。


推荐阅读