wait/notify 在 unique_lock 互斥量上使用 wait/notify 是否安全?
Is it safe to wait/notify on unique_lock mutexes when same mutexes are used with lock_guard on somewhere else?
我正在使用以下一种 wait/signal 方式让线程相互通知。
std::condition_variable condBiz;
std::mutex mutexBar;
..
void Foo::wait()
{
std::unique_lock<std::mutex> waitPoint(mutexBar);
if (waitPoint.owns_lock())
{
condBiz.wait(waitPoint);
}
}
void Foo::signal()
{
std::unique_lock<std::mutex> waitPoint(mutexBar);
condBiz.notify_all();
}
void Foo::safeSection(std::function<void(void)> & f)
{
std::unique_lock<std::mutex> waitPoint(mutexBar);
f();
}
然后将 lock/unlock 机制从 unique_lock 转换为 lock_guard 因为我不会返回 unique_lock 在其他地方使用(wait/signal 除外)并且lock_guard据说开销更少:
void Foo::safeSection(std::function<void(void)> & f)
{
std::lock_guard<std::mutex> waitPoint(mutexBar); // same mutex object
f();
}
而且有效。
这适用于所有平台还是看起来适用于当前平台? unique_lock 和 lock_guard 可以使用相同的互斥对象相互协作吗?
在您的 post 的评论中已经指出,检查 unique_lock 是否在 Foo::wait() 中拥有是没有意义的,因为关联的互斥量必须由在该点锁定以便线程继续进行。
相反,你的条件变量应该检查一些有意义的条件,它应该在 while 循环中或通过使用 condition_variable::wait 的重载来检查一些有意义的条件,它需要一个谓词作为它的第二个参数,这是C++ 标准的效果如下:
while (!pred()) wait(lock);
在 while 循环中检查谓词的原因是,除了条件可能已经满足因此无需等待之外,条件变量可能会虚假地唤醒,即使没有发出这样做的信号。
除此之外,信号线程没有理由不对关联的互斥体使用 lock_guard。但是我不清楚你想做什么。
两者都std::unique_lock
and std::lock_guard
在构造函数中锁定关联的互斥量并在析构函数中解锁它。
std::unique_lock
:
Member functions
(constructor) constructs a unique_lock, optionally locking the supplied mutex
(destructor) unlocks the associated mutex, if owned
和 std::lock_guard
相同:
Member functions
(constructor) constructs a lock_guard, optionally locking the given mutex
(destructor) destructs the lock_guard object, unlocks the underlying mutex
由于两者的行为相同,当用作 RAII 样式包装器时,我认为将它们一起使用没有任何障碍,即使使用相同的互斥体。
我正在使用以下一种 wait/signal 方式让线程相互通知。
std::condition_variable condBiz;
std::mutex mutexBar;
..
void Foo::wait()
{
std::unique_lock<std::mutex> waitPoint(mutexBar);
if (waitPoint.owns_lock())
{
condBiz.wait(waitPoint);
}
}
void Foo::signal()
{
std::unique_lock<std::mutex> waitPoint(mutexBar);
condBiz.notify_all();
}
void Foo::safeSection(std::function<void(void)> & f)
{
std::unique_lock<std::mutex> waitPoint(mutexBar);
f();
}
然后将 lock/unlock 机制从 unique_lock 转换为 lock_guard 因为我不会返回 unique_lock 在其他地方使用(wait/signal 除外)并且lock_guard据说开销更少:
void Foo::safeSection(std::function<void(void)> & f)
{
std::lock_guard<std::mutex> waitPoint(mutexBar); // same mutex object
f();
}
而且有效。
这适用于所有平台还是看起来适用于当前平台? unique_lock 和 lock_guard 可以使用相同的互斥对象相互协作吗?
在您的 post 的评论中已经指出,检查 unique_lock 是否在 Foo::wait() 中拥有是没有意义的,因为关联的互斥量必须由在该点锁定以便线程继续进行。
相反,你的条件变量应该检查一些有意义的条件,它应该在 while 循环中或通过使用 condition_variable::wait 的重载来检查一些有意义的条件,它需要一个谓词作为它的第二个参数,这是C++ 标准的效果如下:
while (!pred()) wait(lock);
在 while 循环中检查谓词的原因是,除了条件可能已经满足因此无需等待之外,条件变量可能会虚假地唤醒,即使没有发出这样做的信号。
除此之外,信号线程没有理由不对关联的互斥体使用 lock_guard。但是我不清楚你想做什么。
两者都std::unique_lock
and std::lock_guard
在构造函数中锁定关联的互斥量并在析构函数中解锁它。
std::unique_lock
:
Member functions
(constructor) constructs a unique_lock, optionally locking the supplied mutex
(destructor) unlocks the associated mutex, if owned
和 std::lock_guard
相同:
Member functions
(constructor) constructs a lock_guard, optionally locking the given mutex
(destructor) destructs the lock_guard object, unlocks the underlying mutex
由于两者的行为相同,当用作 RAII 样式包装器时,我认为将它们一起使用没有任何障碍,即使使用相同的互斥体。