我有一个简单的线程池,需要能够等待其工作人员使用队列中的所有任务而不使用标准thread::join()
,因为我不想自己杀死线程但只是等待让他们在执行循环中完成所有任务。我想用condition_variable
来完成这个,就像这样:
ThreadPool.cpp
void ThreadPool::addTask(ThreadTaskFunction task, void *arg) {
std::lock_guard<std::mutex> t_lock(task_lock);
tasks.push_back(ThreadTask(task, arg));
// For every tasks that is added, I increment a counter
assignedTasks++;
}
void ThreadPool::join() {
std::unique_lock<std::mutex> lock(join_lock);
joinCondition.wait(lock, [this](){
return assignedTasks == 0;
});
}
Thread.cpp 请注意,这是ThreadPool的友好类
void Thread::threadLoop() {
while (!shouldDie) {
ThreadTask task;
if (pool.hasTasks()) {
{
std::lock_guard<std::mutex> lock(pool.task_lock);
if (!pool.hasTasks()) continue;
task = pool.getTask();
}
task.function(task.argument);
this->completeTask();
}
}
this->isThreadFinished = true;
}
void Thread::completeTask() {
std::lock_guard<std::mutex> guard(pool.task_lock);
// When a task is completed, I decrement the counter and notify the main thread that a task has completed.
pool.assignedTasks--;
pool.joinCondition.notify_one();
}
我正在使用这个东西进行物理模拟,这个东西发生在所述模拟的每一步(大约每16ms一次)。发生的事情是,在几百步之后,一切都停止了,因为在主线程进入等待状态之前,以某种方式发送了一个通知信号,这可能是因为它正在检查条件。如果我调试,我可以看到我在计数器上有一个任务,线程上没有任务运行,队列中没有任务,也没有真正发生任何事情。有时,甚至更奇怪,一旦我用断点暂停执行并重新启动它,一切都会解锁。我试过把更多的锁放到位无济于事。 有什么明显的东西我不见了吗?
更新通过将assignedTasks
变量设置为volatile
,似乎可以解决问题。它经常被修改,有时寄存器中的值不会更新,一切都会停止。以前从来没有这样做过。呵呵。 :)
答案 0 :(得分:1)
您正在使用两种不同的互斥锁(join_lock
,pool.task_lock
)在不同时间“保护”assignedTasks
- 这是一种普通的老式竞争条件。