1

我有一个简单的线程池,它需要能够等待其工作人员在不使用标准的情况下消耗队列中的所有任务thread::join(),因为我不想自己杀死线程,而只是等待它们完成所有任务同时停留在他们的执行循环中。我想用condition_variables 来完成这个,像这样:

线程池.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();
}

我正在使用这个东西进行物理模拟,并且这些东西发生在所述模拟的每一步(大约每 16 毫秒一次)。发生的情况是,在几百步之后,一切都停止了,因为在主线程进入等待状态之前以某种方式发送了一个通知信号,可能是因为它正在检查条件。如果我调试,我可以看到我在计数器上剩下一个任务,线程上没有任务运行,队列中没有任务,并且什么都没有发生。有时,更奇怪的是,只要我用断点暂停执行并重新启动它,一切都会解锁。我试过把更多的锁放在适当的位置,但无济于事。我有什么明显的遗漏吗?

更新似乎通过将assignedTasks变量设置为来解决问题volatile。它经常被修改,以至于有时寄存器中的值没有更新,一切都停止了。以前从来没有这样做过。嗯。:)

4

1 回答 1

1

您正在使用两个不同的互斥体 ( join_lock, pool.task_lock) 在不同时间“保护” assignedTasks- 这是一个普通的老式竞争条件。

于 2013-06-10T15:01:55.683 回答