117 votes

Comment propager les exceptions entre les threads?

Nous avons une fonction qui à un seul thread appelle (on appelle cela le thread principal). Dans le corps de la fonction nous frayer plusieurs threads de travail à faire CPU intensive de travail, d'attente pour tous les fils à la fin, puis retourner le résultat sur le thread principal.

Le résultat est que l'appelant peut utiliser la fonction naïvement, et à l'intérieur il va rendre l'utilisation de plusieurs cœurs.

Tout bon jusqu'ici..

Le problème que nous avons est de traiter des exceptions. Nous ne voulons pas des exceptions sur les threads de travail pour le plantage de l'application. Nous voulons que l'appelant de la fonction pour être en mesure de les rattraper sur le thread principal. Nous devons attraper les exceptions sur les threads de travail et les propager à travers le thread principal pour poursuivez le déroulement à partir de là.

Comment pouvons-nous faire cela?

Le mieux je pense est de:

  1. Attraper toute une série d'exceptions sur notre threads de travail (std::exception et quelques-uns de nous-mêmes).
  2. Noter le type et le message de l'exception.
  3. Avoir un correspondant de l'instruction switch sur le thread principal qui renvoie exceptions de ce type a été enregistré sur le thread de travail.

Cela a l'inconvénient de ne supportant un ensemble limité de types d'exception, et aurait besoin d'une modification chaque fois que de nouveaux types d'exceptions ont été ajoutées.

76voto

Anthony Williams Points 28904

Actuellement, le seul portable façon est d'écrire des clauses catch pour tous les types d'exceptions que vous pourriez, comme pour le transfert entre les threads, stocker l'information quelque part à partir de cette clause catch et ensuite l'utiliser plus tard pour renvoyer une exception. C'est l'approche adoptée par Boost.Exception.

Dans C++0x, vous serez en mesure d'intercepter une exception avec catch(...) , puis de le stocker dans une instance de std::exception_ptr l'aide std::current_exception(). Vous pouvez ensuite renvoyer plus tard à partir de la même ou d'un autre thread avec std::rethrow_exception().

Si vous utilisez Microsoft Visual Studio 2005 ou plus tard, puis le juste::thread C++0x bibliothèque de threads soutient std::exception_ptr. (Avertissement: ceci est mon produit).

6voto

paercebal Points 38526

Votre problème est que vous risquez de recevoir plusieurs exceptions, à partir de plusieurs threads, comme chacun a pu échouer, peut-être de raisons différentes.

Je suis en supposant que le thread principal est en quelque sorte d'attente pour les fils à la fin pour récupérer les résultats, ou de contrôler régulièrement les autres threads du progrès, et que l'accès et le partage des données est synchronisé.

La solution la plus Simple

La solution la plus simple serait d'attraper toutes les exceptions dans chaque thread, de les enregistrer dans une variable partagée (dans le thread principal).

Une fois que tous les threads fini, décider quoi faire avec les exceptions. Cela signifie que tous les autres threads ont poursuivi leur traitement, ce qui peut-être, n'est pas ce que vous voulez.

Solution complexe

La plus complexe, la solution est de les avoir chacun de vos fils vérifiez à des points stratégiques de leur exécution, si une exception a été levée à partir d'un autre thread.

Si un thread déclenche une exception, il est pris avant de quitter le fil, à l'exception de l'objet est copié dans certains conteneur dans le thread principal (comme dans la solution la plus simple), et une part variable booléenne est définie sur true.

Et quand un autre thread tests de cette valeur, il voit à l'exécution sera abandonnée, et l'abandonne dans une manière élégante.

Lorsque tous les threads ne avortement, le thread principal peut gérer l'exception en tant que de besoin.

4voto

n-alexander Points 2685

exception levée à partir d'un thread ne sera pas catchable dans le parent de fil. Les Threads sont différents contextes et les meules, et plus généralement le parent fil n'est pas nécessaire de rester là et d'attendre la les enfants à la fin, de sorte qu'il puisse attraper les exceptions. Il suffit de placer dans le code pour que catch():

try
{
  start thread();
  wait_finish( thread );
}
catch(...)
{
  // will catch exceptions generated within start and wait, 
  // but not from the thread itself
}

Vous devrez attraper les exceptions à l'intérieur de chaque fil et d'interpréter l'état de sortie de threads dans le thread principal de re-jeter des exceptions que vous pourriez avoir besoin.

BTW, en l'absence d'une capture dans un fil, elle est mise en œuvre spécifique si le déroulement de pile sera fait à tous, c'est à dire votre automatique des variables destructeurs ne peut même pas être appelé avant de résilier est appelé. Certains compilateurs le faire, mais il n'est pas nécessaire.

3voto

tvanfosson Points 268301

Pourriez-vous sérialiser l'exception dans le thread de travail, transmettre au thread principal, désérialiser, et de le jeter de nouveau? Je pense que pour que cela fonctionne, les exceptions seraient toutes dériver de la même classe (ou au moins un petit ensemble de classes avec l'instruction switch chose de nouveau). Aussi, je ne suis pas sûr qu'ils seraient serializable, je suis juste en pensant à voix haute.

2voto

PierreBdR Points 11479

Il est, en effet, pas de bonne et de façon générique pour transmettre des exceptions à partir d'un thread à l'autre.

Si, comme il se doit, tous vos exceptions dériver de std::exception, alors vous pouvez avoir un haut niveau général exception de capture qui sera en quelque sorte de l'envoyer à l'exception pour le thread principal où il sera relancée. Le problème étant que vous perdez le point de jeter de l'exception. Vous pouvez probablement écrire compilateur dépendant de code pour obtenir ces informations et de les transmettre.

Si tous vos exception hériter de std::exception, alors vous êtes en difficulté et écrire beaucoup de haut-niveau catch dans votre fil ... mais la solution toujours.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X