2017-01-13 1 views
4

J'utilise std :: condition_variable pour chronométrer un signal dans un programme multithread pour contrôler le flux de différentes sections critiques. Le programme fonctionne mais pendant la sortie je suis obligé d'utiliser un prédicat (kill_ == true) pour éviter de détruire des threads qui attendent toujours sur la variable std :: conditionnelle :: wait(). Je ne sais pas si c'est la bonne façon de détruire tous les fils d'attente, conseils sollicités. Voici un extrait de code:Bonne façon de détruire les threads en attente sur une variable std :: conditional_variable lors de la sortie du programme principal

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

Avez-vous essayé ['notify_all'] (http://www.cplusplus.com/reference/condition_variable/condition_variable/notify_all/)? – iammilind

+1

Problème de terminologie: voulez-vous terminer les threads ou les laisser s'exécuter jusqu'à la fin? Que considérez-vous par «destruction du fil»? –

Répondre

3

C'est généralement ainsi que je gère la destruction de mes threads en attente. Vous voulez une section de code tel que celui-ci où vous souhaitez effectuer le nettoyage (dans un destructor de classe, le thread principal avant la sortie de processus, etc.):

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

Je suppose que timer::section() exécutait dans les un peu de fil std::thread thread1.

La durée de propriété du mutex est contrôlée par le bloc scoped. Vous aurez besoin du mutex uniquement lorsque vous définissez kill_ = true et que vous le relâcherez avant d'appeler le .notify_all() (sinon le thread réveillé pourrait trouver le verrou toujours maintenu et se rendormir).

Bien sûr, std :: utilisation de unique_lock ressemblerait à ceci:

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

Il est de préférence personnelle dans une large mesure ... les deux sections de code accomplir la même tâche.

+0

Merci pour les commentaires. Timer est un sous-ensemble d'un autre objet et il existera tout au long de la vie du programme (thread.detach() utilisé). Et le signal kill_ (= const) sera défini à partir du programme principal uniquement pendant la sortie. std :: unique_guard est préféré à lock_guard pour autoriser le verrouillage/déverrouillage. – ark1974

+0

Ajout de commentaires sur std :: lock_guard et std :: unique_lock. –