Min*_*ine 5 c++ multithreading mutex locking c++11
使用C ++ 11 std::thread
,std::mutex
我正在编写一个简单的工作线程。但是,我在std::mutex
lock中遇到了一个奇怪的挂起问题,它看起来好像两个线程(主线程和工作线程)都试图锁定互斥锁,但是都被阻塞了。
这是完整的代码
#include <thread>
#include <condition_variable>
#include <memory>
#include <iostream>
#include <list>
std::condition_variable cv;
std::mutex m;
std::thread t;
bool shouldExit = false;
std::list<int> jobs;
void thread_func()
{
std::unique_lock<std::mutex> lock(m);
while (!shouldExit) {
while (jobs.empty() && !shouldExit) {
cv.wait(lock);
}
// Do some stuff
if (jobs.empty()) {
continue;
}
// Get a job and do something with it
if (!lock.owns_lock()) {
lock.lock(); // <<<< Worker thread hang here
}
auto j = std::move(jobs.front());
jobs.pop_front();
lock.unlock();
std::cout << "Do something with job " << j << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
}
int main()
{
t = std::thread(thread_func);
for (int i = 1; i < 100; ++i) {
std::cout << "Push to job " << i << std::endl;
{
std::lock_guard<std::mutex> lock(m); // <<<< main thread hang here
jobs.push_back(i);
cv.notify_one();
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
// To wait for thread exit
shouldExit = true;
cv.notify_one();
t.join();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我正在Ubuntu 14.04上使用以下命令编译代码
g++ -std=c++11 -g -O0 -pthread -o testthread testthread.cpp
Run Code Online (Sandbox Code Playgroud)
执行结果通常是这样的:
$ ./testthread
Push to job 1
Do something with job 1
Push to job 2
Do something with job 2
Push to job 3
Push to job 4
Run Code Online (Sandbox Code Playgroud)
有趣的部分是,当我将主线程中sleeping-1ms的一个行代码移到下面的代码中时lock_guard
,问题就消失了。
for (int i = 1; i < 100; ++i) {
std::cout << "Push to job " << i << std::endl;
{
std::lock_guard<std::mutex> lock(m);
jobs.push_back(i);
cv.notify_one();
std::this_thread::sleep_for(std::chrono::milliseconds(1)); // Moved into lock_guard
}
}
Run Code Online (Sandbox Code Playgroud)
我不知道为什么。您能否帮助解释代码的行为以及我做错了什么?
[更新]我知道以某种方式重写工作线程可以解决此问题。但是我仍然想在原始代码中知道当两个线程锁定互斥锁但都被阻塞时会发生什么情况。
cv.wait
在未锁定的情况下调用是未定义的行为lock
。添加这个断言:
while (!shouldExit) {
assert(lock.owns_lock()); // <------ add this
while (jobs.empty() && !shouldExit) {
cv.wait(lock);
}
Run Code Online (Sandbox Code Playgroud)
libc++ 将从wait
if抛出!lock.owns_lock()
,但我不知道其他实现会做什么。