Переменная условия ложного пробуждения / кругового задания - PullRequest
0 голосов
/ 21 декабря 2018

Я новичок в потоке C ++ и пытаюсь написать менеджер задач с циклическим перебором (кооперативный), используя потоки C ++.Действительно ли объявление round_robin_task_ulock ниже допустимо - это глобальная статическая переменная.Я хочу отложить блокировку мьютекса до тех пор, пока не запустится поток диспетчера задач.

static std::mutex                      round_robin_task_mutex;
static std::condition_variable         task_manager_cvar; 
static thread                          round_robin_task_manager_thread;
static std::unique_lock<std::mutex>    
     round_robin_task_ulock(round_robin_task_mutex, std::defer_lock);

static void round_robin_task_manager()
{
    round_robin_task_ulock.lock();
    //..
}

Когда поток диспетчера задач запущен, он может запустить задачу циклического перебора с уведомлением с последующим ожиданием

 round_robin_tasks[current_task_id].task_cvar.notify_one();
 // release the mutex and go to sleep
 task_manager_cvar.wait(round_robin_task_ulock); 
 // now we own the mutex again

и когда задача циклического перебора хочет приостановить себя, она уведомляет поток диспетчера задач

 task_manager_cvar.notify_one();
 round_robin_tasks[current_task_id].task_cvar.wait
                  (round_robin_task_ulock, [] { return  
                      round_robin_tasks[my_task_id].task_running_now; } );

Есть ли очевидные проблемы с этим?Я читал о ложных следах.Возможно ли, что ложное пробуждение может разбудить поток диспетчера задач, пока задача круглого робота все еще владеет мьютексом, или гарантируется, что при возврате функции ожидания мьютекс всегда принадлежит (заблокирован) потоку, вызвавшему ожидание.

1 Ответ

0 голосов
/ 21 декабря 2018

Вы должны построить свой код так, чтобы без какой-либо переменной условия он все еще работал.Если он будет работать, если он заблокировал мьютекс, проверил условие, разблокировал мьютекс и сразу повторил цикл, тогда он будет работать с условной переменной, только более эффективно.

Реализация могла бы вызывать переменные условия каждые 10 миллисекунд, если бы захотелось по какой-то причине, или было какое-то странное взаимодействие с такими инструкциями, как MWAIT, строки кэша и транзакционные блокировки или некоторые другие.другая странная аппаратная особенность.

Кажется, я вспоминаю чтение об архитектуре, которая будет сигнализировать о событиях ожидания в ячейках памяти всякий раз, когда записывается какая-либо часть этой строки кэша.И библиотека потоков не дополнила структуру до размера строки кэша.

Так что ДА вам, возможно, придется обрабатывать сотни пробуждений в секунду, и ваш код все равно должен работать правильно.

Из того, что я вижу из того, что вы написали, у вас есть только одно место, в котором вы проверяете предикат , то есть условие, которое должно быть истинным, чтобы пройти через это условие.И перед каждым уведомлением вы должны были обновить предикат.Предикат всегда должен быть записан или прочитан, в то время как он защищен той же блокировкой, что и переменная условия.

Если вам нужно другое поведение, вы можете использовать семафор .

...