我正在使用这段代码来处理一个线程池。在多次调用RunTask之后(有问题的任务是一个休眠5秒的方法),然后我调用Wait()试图等待所有线程完成。代码在Wait()mehhod中挂起。我怀疑它是我对条件变量的管理,但我无法弄明白。
class lthThreadHandler {
public:
lthThreadHandler(int pool_size)
{
mAvailable = pool_size;
mRunning = true;
for (int i = 0; i < pool_size; ++i)
mThreads.create_thread(boost::bind(<hThreadHandler::pool_main, this));
}
template<typename Task>
void RunTask(Task task)
{
boost::unique_lock<boost::mutex> lock(mMutex);
// If no threads are available, then return.
if (0 == mAvailable)
return;
// Decrement count, indicating thread is no longer available.
--mAvailable;
// Set task and signal condition variable so that a worker thread will
// wake up andl use the task.
mTasks.push(boost::function<void()>(task));
mCondition.notify_one();
}
void Wait() {
try {
mThreads.join_all();
}
// Suppress all exceptions.
catch (...) {
}
}
/// @brief Entry point for pool threads.
void pool_main() {
while (mRunning) {
// Wait on condition variable while the task is empty and the pool is
// still running.
boost::unique_lock<boost::mutex> lock(mMutex);
while (mTasks.empty() && mRunning) {
mCondition.wait(lock);
}
// If pool is no longer running, break out.
if (!mRunning)
break;
// Copy task locally and remove from the queue. This is done within
// its own scope so that the task object is destructed immediately
// after running the task. This is useful in the event that the
// function contains shared_ptr arguments bound via bind.
{
boost::function<void()> task = mTasks.front();
mTasks.pop();
lock.unlock();
// Run the task.
try {
task();
}
// Suppress all exceptions.
catch (...) {
}
}
// Task has finished, so increment count of available threads.
lock.lock();
++mAvailable;
} // while mRunning
}
private:
std::queue<boost::function<void()> > mTasks;
boost::thread_group mThreads;
std::size_t mAvailable;
boost::mutex mMutex;
boost::condition_variable mCondition;
bool mRunning;
};
此代码段来自另一个SO答案:Thread pool using boost asio
答案 0 :(得分:0)
Wait
无限期挂起,因为只要你不清除mRunning
,线程都会运行无限循环。即使你因为数据争用而做it might change your pet into a bag of popcorn。
因此。基本上你诅咒某人完美的taskqueue / threadpool实现。主要是通过闲置重命名¹然后
Wait()
,而不做任何事情导致这些线程完成。mRunning
旗帜即使您将原始析构函数逻辑放入Wait()
,请记住,您实际上会遇到竞争条件,即在(主)线程重置{{1}之前无法保证已发布的任务将运行国旗。
我建议你不要干涉代码。
我有一些类似的线程,你可能会发现[SO]上更容易理解,所以你可以比较一下:
之前我曾回答过一个类似的问题(回应你从成员函数而不是析构函数中尝试mRunning
的事实:
这个答案对你解释为什么这种功能很棘手很有帮助。
¹join_all
,真的吗?线程管理员,真的吗?所有的名字最初选择得更好。