标题基本上说明了一切。如果我使用特定条件和互斥锁调用pthread_cond_wait,那么该线程是否会被阻塞,直到用相应的条件调用pthread_cond_signal?或者无论是否随后再次解锁互斥锁,它都会解锁?
如果答案是前者,我会进行跟进。我有一个队列用于我的线程之间的消息传递。我想确保一次只有一个线程可以将一个项目附加到队列中(因此使用互斥锁)。没有任何线程知道是否有任何其他线程会等待自己掌握互斥锁。
当尝试将一个项目附加到队列时,我锁定互斥锁,等待队列没有填满pthread条件,然后执行追加,然后解锁互斥锁。在解锁之前,我应该执行pthread_cond_signal,即使我不知道是否还有其他线程在等待?如果多个线程在等待会发生什么?
答案 0 :(得分:6)
有人需要发信号/广播条件变量,否则等待线程不会必然被唤醒。你也可以得到“虚假”的唤醒,但不要依赖它们。一旦服务员被唤醒(通过信号或广播或虚假),它将开始尝试获取互斥锁,并且一旦 pthread_cond_wait
返回。
如果有多个线程在等待,则其中一个线程被唤醒(任意或根据实现记录的规则)。在您描述的代码中,线程在此condvar上等待的唯一位置是它尝试将项添加到完整队列时。所以你有三个选择:
会发出条件变量信号。这会唤醒0个或更多服务员中的一个。如果队列仍未满,则在添加元素后再次发出信号,以防有超过1名服务员。
广播条件变量。现在添加元素后无需发出信号。
每次删除元素时都会发出条件变量信号,无论队列是否已满。如果你这样做,不要在以后改变代码的错误,一次删除两个元素,只发信号一次。条件变量每次发出信号时都会减少一个服务员的数量,这种方法有效,因为它可以防止同时至少有一个服务员,和更少的唤醒前服务员试图获取互斥锁比那里是队列中的空格。因此,当他们可以使用空间时,你永远不会让线程等待。
想到这一点的方法是,你正在等待的“条件”是“队列未满”。只要条件变为为真,您就应该发信号或广播条件变量。如果您选择发信号,并且可能有多个服务员,则每个服务员需要发出信号(唤醒下一个服务员),如果条件在完成其后仍然为真。
如果你不关心一些额外的上下文切换的性能成本,并且你已经编写了正确等待condvar以应对虚假唤醒的代码,那么在发出condvar信号或广播时也是安全的。条件仍然是假的。这是关于条件变量的好东西之一,它使得更容易推断代码的正确性。因此,“只要条件成立,您应该发出信号或广播条件变量”的要求仅表示它所说的内容。如果并且仅当条件成立时,您不必发出信号。
因此,在这种情况下,每次从队列中删除元素时都会发出信号,无论事先是否已满。在这种情况下,很容易将信号的数量减少到必要的最小值,但偶尔会比确定条件是否变为真值更麻烦,所以相反,你发出信号是否现在是真的并且可能之前是假的,或者甚至只是发出信号可能现在是真的。我不建议无缘无故地加入更多的尾声,但有时它会使代码变得更简单。
答案 1 :(得分:1)
一旦{a}条件变量发出信号并且b)另一个线程已解锁互斥锁,则pthread_cond_wait
调用将解锁。然后pthread_cond_wait
将锁定互斥锁并返回。
(请注意,在pthread_cond_wait
返回后,您几乎总是需要重新检查您的真实测试,例如“队列是否已满?”。通常您会在while
循环中调用它因为这个原因。)
您无法使用pthread API检查是否有其他线程正在等待条件变量,因此正常模式是在解锁互斥锁之前调用pthread_cond_signal
或pthread_cond_broadcast
。如果没有人在等,这些便宜。
“信号”和“广播”之间的区别是前者仅唤醒一个等待线程(并且没有指定哪一个),而后者唤醒所有这些线程。
我认为在你的情况下,你应该每次从队列中删除一个项目时“广播”,让插入线程知道他们有一个镜头。然后,您无需发出插入来自其他插入的线程的信号。
答案 2 :(得分:1)
当您将一个项目放入队列时,如果队列先前为空,则发出条件变量信号 - 这样您就可以唤醒可能等待从队列中获取项目的线程。如果队列不为空,则没有理由让提取线程阻塞该条件,因此不需要信号。
当您从队列中获取项目时,如果队列先前已完全填满,则发出另一个条件变量 - 这样您就可以唤醒可能等待将项目放入队列的线程。如果队列未满,则没有理由让附加线程阻塞该条件,因此不需要信号。
不要广播,除非您从队列中获取/放置多个项目。如果只放一个项目,请分别说。只提供一个插槽并播放,你将唤醒所有线程,但只有一个能够取得进展,所有其他人将回去等待并唤醒他们,他们恢复并重新入睡将是一个纯粹的开销。
答案 3 :(得分:0)
1是的。与pthread_cond_wait()
调用关联的互斥锁由函数解锁。
2任何等待该条件的线程都可以恢复。当pthread_cond_wait()
返回时,关联的互斥锁将被锁定。
pthread_cond_wait
自动解锁互斥锁(根据pthread_unlock_mutex)并等待 对于要发信号通知的条件变量cond。线程执行 被暂停,并且在该条件之前不消耗任何CPU时间 变量发出信号。必须在进入pthread_cond_wait时由调用线程锁定互斥锁。 返回之前 调用线程,pthread_cond_wait重新获取互斥锁(按照 pthread_lock_mutex)。