我正在调查当我试图阻止它时我的工作线程死锁的问题。
这是有问题的最小版本:
#include <atomic>
#include <condition_variable>
#include <functional>
#include <iostream>
#include <memory>
#include <mutex>
#include <thread>
#include <vector>
class Worker
{
private:
std::atomic<bool> m_running;
std::condition_variable m_cond;
std::mutex m_mutex;
std::function<void()> m_workItem;
std::thread m_thread;
public:
Worker() :
m_running(true),
m_thread(std::bind(&Worker::DoWork, this))
{
}
~Worker()
{
Stop();
m_thread.join();
}
bool QueueWork(std::function<void()> item)
{
std::unique_lock<std::mutex> padlock(m_mutex);
if (m_workItem)
{
return false;
}
m_workItem = item;
padlock.unlock();
m_cond.notify_all();
return true;
}
void Stop()
{
bool expected = true;
if (m_running.compare_exchange_strong(expected, false))
{
m_cond.notify_all();
}
}
private:
void DoWork() noexcept
{
while (m_running)
{
std::unique_lock<std::mutex> padlock(m_mutex);
m_cond.wait(padlock,
[this]
()
{
return !m_running || m_workItem;
});
if (m_workItem)
{
decltype(m_workItem) workItem;
std::swap(m_workItem, workItem);
padlock.unlock();
workItem();
}
}
}
};
int main()
{
std::cout << "Start." << std::endl;
{
std::vector<std::unique_ptr<Worker>> workers;
for (int i = 0; i < 10; ++i)
{
workers.push_back(std::unique_ptr<Worker>(new Worker()));
}
workers[0]->QueueWork(
[]()
{
std::cout << "Work item" << std::endl;
});
std::this_thread::sleep_for(std::chrono::milliseconds(10));
for (auto & worker : workers)
{
worker->Stop();
}
for (auto & worker : workers)
{
worker.reset();
}
}
std::cout << "Stop." << std::endl;
return 0;
}
我们的想法是,当从主机线程调用Worker::Stop()
时,Worker::m_running
设置为false
,notify_all()
会调用Worker::m_cond
。工作线程从其m_cond.wait()
中醒来,检查m_running
并中断,退出线程函数。
m_running
是true
(这怎么可能?)并返回wait()
。没有对m_cond.notify_all()
的额外调用,因此线程最终处于死锁状态。
我在此代码中生成了10个Worker
个对象。我不认为它与线程数有任何关系,但是为了能够触发竞争条件(如果它就是这样),我需要更多的线程。
代码有什么问题?
运行gcc:
g++ --version
g++ (Ubuntu 4.9.2-0ubuntu1~14.04) 4.9.2
Copyright (C) 2014 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
使用编译:
g++ -std=c++11 -pedantic test.cpp -lpthread
编辑:
更改了Worker
个私人成员的顺序。 m_thread
现在是最后一次。仍然是同样的问题。