web-dev-qa-db-fra.com

C++ 11: Que se passe-t-il si vous n'appelez pas join () pour std :: thread

Donnée ci-après:

void test() 
{
  std::chrono::seconds dura( 20 );
  std::this_thread::sleep_for( dura );
}

int main()
{
  std::thread th1(test);
  std::chrono::seconds dura( 5 );
  std::this_thread::sleep_for( dura );
  return 0;
}

main quittera après 5 secondes, que va-t-il arriver à th1 qui est toujours en cours d'exécution?

Est-ce qu'il continue à s'exécuter jusqu'à la fin, même si l'objet de fil th1 que vous avez défini dans main sort de la portée et est détruit?

Est-ce que th1 reste simplement là après la fin de son exécution ou est en quelque sorte nettoyé à la fin du programme?

Que se passe-t-il si le thread a été créé dans une fonction et non pas main - le thread reste-t-il en place jusqu'à la fin du programme ou lorsque la fonction sort de la portée?

Est-il prudent de ne pas appeler join pour un thread si vous voulez un type de comportement de délai d'attente sur le thread?

28
kiki

Si vous n'avez pas détaché ou rejoint un thread lorsque le destructeur est appelé, il appellera std::terminate, nous pouvons le voir en consultant le draft C++ 11 standard nous voyons que la section 30.3.1.3thread destructor dit:

Si joinable (), appelle std :: terminate (). Sinon, n'a aucun effet. [ Remarque: Détachez implicitement ou joignez un thread joinable () dans son destructeur pourrait rendre difficile le débogage de la correction (pour détachement) ou des bogues de performance (pour la jointure) rencontrés uniquement lorsqu’un l'exception est levée. Ainsi, le programmeur doit s'assurer que le destructor n'est jamais exécuté tant que le thread est encore joignable. -fin Remarque ]

en ce qui concerne les raisons de ce comportement, nous pouvons trouver un bon résumé dans (Not) à l'aide de std :: thread

Pourquoi le destructeur d'un thread joignable doit-il appeler std :: terminer? Après tout, le destructeur pourrait rejoindre l’enfant thread, ou il pourrait se détacher du thread enfant, ou il pourrait annuler le fil. En bref, vous ne pouvez pas rejoindre le destructeur comme cela le ferait entraîner un programme inattendu (non indiqué explicitement dans le code) geler dans le cas où f2 jette.

et un exemple suit et dit aussi:

Vous ne pouvez pas détacher car cela risquerait la situation où le fil principal laisse la portée dans laquelle le thread enfant a été lancé et l'enfant Le thread continue à fonctionner et conserve les références à la portée qui est déjà disparu.

L'article fait référence à N2802: Un appel à réexaminer le détachement sur destruction pour les objets de thread qui est un argument contre la proposition précédente qui était détaché lors de la destruction si joignable et il note qu'une des deux alternatives serait de joindre qui conduire à des impasses, l’autre alternative est ce que nous avons aujourd’hui, à savoir std::terminate sur destruction si joignable.

19
Shafik Yaghmour

En C++ 11, vous devez spécifier explicitement "que se passe-t-il" lorsque le thread nouvellement créé sort de son périmètre (son nom est appelé). Parfois, lorsque nous sommes sûrs que le thread principal continue et que nos threads agissent comme un "pipeline", il est prudent de les "détacher ()"; et parfois, lorsque nous attendons que nos threads WORKER terminent leurs opérations, nous les rejoignons ().

Comme this , le programmeur doit s'assurer que le destructeur n'est jamais exécuté tant que le thread est encore joignable.

Spécifiez votre stratégie multithread. Dans cet exemple, std::terminate() est appelé.

1
mkr