C++:互斥锁从通知程序到服务员的传递是无缝的吗?
C++: Is the passing of a mutex from a notifier to a waiter seamless?
在多线程环境下,我们有以下两个函数:
std::mutex mtx;
std::condition_variable cv;
void waiter()
{
std::unique_lock<std::mutex> lck(mtx);
//...
cv.wait(lck);
//...
}
void notifier()
{
std::unique_lock<std::mutex> lck(mtx);
//...
cv.notify_one();
}
假设服务员先执行,然后等待condition_variable。然后通知程序执行并通知服务员。等待者在通知者释放后尝试重新获取互斥锁。
问题:是否有可能其他线程在通知程序释放互斥量之后但在等待者获取它之前就锁定了互斥量?如果是,必须做些什么才能避免这种情况发生?如果是的话,我也不明白 condition_variable 的目的。目的应该是阻塞线程直到满足某些条件。但是,如果条件满足,线程被唤醒后,有可能再次条件不满足,那又有什么意义呢?
Is it possible that some other thread locks the mutex right after the notifier has released it but still before the waiter gets it?
是的。
If yes, what has to be done so that this cannot happen?
没有。
And if yes, I also don't understand the purpose of condition_variable. The purpose should be to block a thread until some condition is fulfilled. But if, after the condition is fulfilled and the thread has been woken up, there is the chance that again the condition is not fulfilled, what's the point?
更复杂。如果根本没有通知条件变量,则线程可以被唤醒。这称为虚假唤醒 (doc)。
条件变量的要点是阻塞一个线程,直到其他线程通知它。为了解决 "condition is not fulfilled when the waiting thread gets a chance to execute" 问题,等待线程通常在循环中等待,直到满足条件。标准库甚至有一个快捷方式,有一个 void wait( std::unique_lock<std::mutex>& lock, Predicate pred );
重载可以做到这一点。见 doc.
在多线程环境下,我们有以下两个函数:
std::mutex mtx;
std::condition_variable cv;
void waiter()
{
std::unique_lock<std::mutex> lck(mtx);
//...
cv.wait(lck);
//...
}
void notifier()
{
std::unique_lock<std::mutex> lck(mtx);
//...
cv.notify_one();
}
假设服务员先执行,然后等待condition_variable。然后通知程序执行并通知服务员。等待者在通知者释放后尝试重新获取互斥锁。
问题:是否有可能其他线程在通知程序释放互斥量之后但在等待者获取它之前就锁定了互斥量?如果是,必须做些什么才能避免这种情况发生?如果是的话,我也不明白 condition_variable 的目的。目的应该是阻塞线程直到满足某些条件。但是,如果条件满足,线程被唤醒后,有可能再次条件不满足,那又有什么意义呢?
Is it possible that some other thread locks the mutex right after the notifier has released it but still before the waiter gets it?
是的。
If yes, what has to be done so that this cannot happen?
没有。
And if yes, I also don't understand the purpose of condition_variable. The purpose should be to block a thread until some condition is fulfilled. But if, after the condition is fulfilled and the thread has been woken up, there is the chance that again the condition is not fulfilled, what's the point?
更复杂。如果根本没有通知条件变量,则线程可以被唤醒。这称为虚假唤醒 (doc)。
条件变量的要点是阻塞一个线程,直到其他线程通知它。为了解决 "condition is not fulfilled when the waiting thread gets a chance to execute" 问题,等待线程通常在循环中等待,直到满足条件。标准库甚至有一个快捷方式,有一个 void wait( std::unique_lock<std::mutex>& lock, Predicate pred );
重载可以做到这一点。见 doc.