【发布时间】:2016-02-25 19:38:58
【问题描述】:
我有以下问题。我有一些做一些工作的多个线程和一个在工作可用时唤醒它们的主线程。到目前为止,我已经设法使用条件变量和互斥锁编写了一些代码,并且大多数情况下这工作正常,但有时,通知线程会在调用 notify_one() 后立即锁定互斥锁,从而阻塞通知线程并死锁.
我已经编写了最少的代码来说明这种情况。
#include <iostream>
#include <thread>
#include <condition_variable>
std::mutex lock;
std::condition_variable cv;
void foo() {
std::cout << "Thread: Entering doWork()" << std::endl;
std::unique_lock<std::mutex> l(lock);
std::cout << "Thread: Acquired lock, going to wait." << std::endl;
cv.wait(l , []{return true;});
std::cout << "Thread: Done waiting, exit." << std::endl;
}
int main(void) {
std::unique_lock<std::mutex> l(lock);
std::cout << "MAIN: Creating thread." << std::endl;
std::thread t(foo);
std::cout << "MAIN: Unlocking mutex." << std::endl;
l.unlock();
std::cout << "MAIN: Notifying thread." << std::endl;
cv.notify_one();
//std::this_thread::sleep_for(std::chrono::seconds(1));
l.lock();
std::cout << "MAIN: Acquired lock." << std::endl;
std::cout << "MAIN: Joining thread." << std::endl;
t.join();
return 0;
}
理想情况下,输出应该是
MAIN: Creating thread.
MAIN: Unlocking mutex.
Thread: Entering doWork()
Thread: Acquired lock, going to wait.
MAIN: Notifying thread.
Thread: Done waiting, exit.
MAIN: Acquired lock.
MAIN: Joining thread.
但更多时候是这样
MAIN: Creating thread.
MAIN: Unlocking mutex.
MAIN: Notifying thread.
MAIN: Acquired lock.
MAIN: Joining thread.
Thread: Entering doWork()
除了在通知线程中添加睡眠(我不想这样做)之外,有没有更好的方法来消除死锁的机会?提前谢谢你。
【问题讨论】:
-
您的
cv.wait()不处理虚假唤醒。根据en.cppreference.com/w/cpp/thread/condition_variable/wait:原子地释放锁,阻塞当前正在执行的线程,并将其添加到等待 *this 的线程列表中。执行 notify_all() 或 notify_one() 时,线程将被解除阻塞。它也可能被虚假地解除阻塞。解除阻塞后,无论什么原因,都会重新获取锁并等待退出。 -
您已经错过了
notify/wait方案的全部逻辑!你忘了实现你正在等待的东西,改变线程需要通知的东西!你有一个wait不等待 任何事情,还有一个notify不通知 任何事情! -
@AndrewHenle,线程确实释放了锁,这就是
unique_lock的用途。如果它测试了一个适当的条件,它会处理虚假唤醒,而不仅仅是[]{ return true;},因为谓词在它醒来时会被测试,如果谓词是假的,它会再次等待。 -
@JonathanWakely-Doh!固定的。谢谢!
-
对于第一个问题,unique_lock 的析构函数解锁了关联的互斥锁。对于第二个,你能更具体一点吗?
标签: multithreading c++11 deadlock