2017-01-13 3 views
4

Я использую std :: conditional_variable для синхронизации сигнала в многопоточной программе для управления потоком различных критических секций. Программа работает, но во время выхода я вынужден использовать предикат (kill_ == true), чтобы избежать уничтожения потоков, которые все еще ждут на std :: conditional_variable :: wait(). Я не знаю, правильно ли он уничтожил все ожидающие потоки, и попросил совета. Вот фрагмент кода:Правильный способ уничтожения потоков, ожидающих на std :: conditional_variable во время выхода основной программы

class timer 
{ 
    // ... 
     timer(std::shared_ptr<parent_object> parent,const bool& kill) 
     :parent_(parent),kill_(kill){} 

    private: 
     std::condition_variable cv_command_flow_; 
     std::mutex mu_flow_; 
     const bool& kill_; 
     std::shared_ptr<parent_object> parent_; 
}; 

void timer::section() 
{ 
     auto delay = get_next_delay(); 

     std::unique_lock<std::mutex> lock(mu_flow_); 
     std::cv_command_flow_.wait_until(lock,delay,[] { return kill_ == true; }); 

     if(kill_) return; 

     parent_->trigger(); 

     std::cv_command_exec_.notify_all(); 
} 
+0

Вы пробовали ['notify_all'] (http://www.cplusplus.com/reference/condition_variable/condition_variable/notify_all/)? – iammilind

+1

проблема терминологии: вы хотите прекратить потоки или позволить им работать до конца. что вы считаете «уничтожением нитей»? –

ответ

3

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

{ 
    std::lock_guard<std::mutex> lock(mu_flow); 
    kill_ = true; 
} 
cv_command_exec_.notify_all(); 
thread1.join(); 

Я предполагаю, что timer::section() выполнял в какой-нить std::thread thread1.

Длительность владения мьютексом контролируется областью действия. Вы хотите, чтобы мьютексы удерживались только при установке kill_ = true и отпускались до того, как вы звоните .notify_all() (иначе просыпавшаяся нить может обнаружить, что замок все еще удерживается и возвращается спать).

Конечно, использование станд :: unique_lock будет выглядеть так:

std::unique_lock<std::mutex> lock(mu_flow); 
kill_ = true; 
lock.unlock(); 
cv_command_exec_.notify_all(); 
thread1.join(); 

Это личное предпочтение в значительной степени ... обе секции кода выполнить ту же задачу.

+0

Спасибо за отзыв. Таймер - это подмножество другого объекта, и он будет существовать на протяжении всей жизни программы (используется thread.detach()). И сигнал kill_ (= const) будет установлен из основной программы только во время выхода. std :: unique_guard является предпочтительным по сравнению с lock_guard, чтобы разрешить блокировку/разблокировку. – ark1974

+0

Добавлены комментарии к std :: lock_guard и std :: unique_lock. –

Смежные вопросы