У меня есть простой пул потоков, который должен ждать, пока его рабочие будут потреблять все задачи в очереди, не используя стандартный thread::join()
, так как я не хочу убивать сами темы но просто подождите, пока они завершат все задания, оставаясь в циклах выполнения. Я думал, что достичь этого с помощью condition_variable
с, например, так:C++ 11 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();
}
Я использую эту вещь для моделирования физики, и это происходит на каждом этапе моделирования (примерно раз каждые 16 мс). Случается, что после нескольких сотен шагов все останавливается, потому что какой-то сигнал уведомления отправляется до, главный поток входит в состояние ожидания, вероятно, потому, что он проверяет условие. Если я отлаживаю, я вижу, что у меня есть одна задача, оставленная на счетчике, никаких задач, выполняемых в потоках, нет задач в очереди, и ничего больше не происходит. Иногда, даже более странно, все разблокируется, как только я приостанавливаю выполнение с точкой останова и перезапускаю его. Я попытался поставить больше замков на место безрезультатно. Есть ли что-то очевидное, что мне не хватает?
UPDATE Оказывается, что эта проблема решается путем установки переменной assignedTasks
в volatile
. Он так часто изменяется, что иногда значение в регистрах не обновляется, и все останавливается. Никогда раньше это не делалось. Да. :)
Присоединиться не убивает нити, он ждет их завершения – doctorlove
Но я не хочу, чтобы они закончили, я просто хочу, чтобы они закончили свою задачу, а затем зациклились, ожидая большего. Я хочу, чтобы дождаться завершения всех текущих задач, чтобы я мог запланировать еще больше, не запустив новые потоки, но использую те, которые у меня уже есть. – juandemarco