web-dev-qa-db-fra.com

Comment terminer un thread en C ++ 11?

Je n'ai pas besoin de terminer le thread correctement ou de le faire répondre à une commande "terminate". Je suis intéressé à terminer le thread avec force en utilisant pur C++ 11.

114
Alexander V
  1. Vous pouvez appeler std::terminate() depuis n'importe quel fil et le fil auquel vous faites référence se termine avec force.

  2. Vous pouvez organiser l'exécution de ~thread() sur l'objet du thread cible, sans l'intervention de join() ni detach() sur cet objet. Cela aura le même effet que l'option 1.

  3. Vous pouvez concevoir une exception avec un destructeur qui lève une exception. Et puis arrangez-vous pour que le thread cible lève cette exception quand elle doit être terminée de force. La partie délicate de celui-ci est d’obtenir que le thread cible lève cette exception.

Les options 1 et 2 ne perdent pas de ressources intra-processus, mais se terminent par tous les threads.

L'option 3 perdra probablement des ressources, mais est partiellement coopérative en ce sens que le thread cible doit accepter d'exécuter l'exception.

Il n’existe pas de méthode portable dans C++ 11 (à ma connaissance) pour tuer un seul thread dans un programme multi-thread (c’est-à-dire sans tuer tous les threads). Il n'y avait aucune motivation pour concevoir une telle fonctionnalité.

Un std::thread peut avoir cette fonction membre:

native_handle_type native_handle();

Vous pourrez peut-être l'utiliser pour appeler une fonction dépendante du système d'exploitation pour faire ce que vous voulez. Par exemple, sur les systèmes d'exploitation Apple, cette fonction existe et native_handle_type est un pthread_t. Si vous réussissez, vous risquez de perdre des ressources.

116
Howard Hinnant

La réponse de @Howard Hinnant est correcte et complet. Mais cela pourrait être mal compris s'il est lu trop rapidement, parce que std::terminate() (processus complet) a le même nom que le "terminateur" que @AlexanderVX avait à l'esprit (1 fil).

Résumé: "mettre fin à 1 thread + avec force (le thread cible ne coopère pas) + pur C++ 11 = No way."

34
Nanno Langstraat

Cette question a en réalité une nature plus profonde et une bonne compréhension des concepts du multithreading en général vous donnera un aperçu de ce sujet. En fait, il n'y a pas de langage ou de système d'exploitation qui vous offre des possibilités de terminaison de threads soudaine et asynchrone sans vous avertir de ne pas les utiliser. Et tous ces environnements d’exécution conseillent vivement aux développeurs, voire exigent même de construire des applications multithreading, sur la base d’une terminaison de thread coopérative ou synchrone. La raison de ces décisions et conseils communs est qu’ils sont tous construits sur le même modèle général multithreading.

Comparons les concepts de multitraitement et de multitraitement pour mieux comprendre les avantages et les inconvénients du second.

Le multitraitement suppose la scission de tout l'environnement d'exécution en un ensemble de processus complètement isolés contrôlés par le système d'exploitation. Process incorpore et isole l'état de l'environnement d'exécution, y compris la mémoire locale du processus, des données qu'il contient et de toutes les ressources système telles que les fichiers, les sockets et les objets de synchronisation. L'isolation est une caractéristique essentielle du processus car elle limite la propagation des erreurs par les limites du processus. En d'autres termes, aucun processus ne peut affecter la cohérence d'un autre processus dans le système. Il en va de même pour le comportement du processus, mais de manière moins restrictive et plus floue. Dans un tel environnement, n'importe quel processus peut être tué à n'importe quel moment "arbitraire", car tout processus est d'abord isolé, d'autre part, le système d'exploitation a une connaissance complète de toutes les ressources utilisées par processus et peut les libérer sans fuir, et le processus sera tué par OS pas vraiment à un moment arbitraire, mais dans le nombre de points bien définis où l'état du processus est bien connu.

En revanche, le multithreading suppose l’exécution de plusieurs threads dans le même processus. Mais tous ces threads partagent la même boîte d'isolation et il n'y a pas de contrôle du système d'exploitation de l'état interne du processus. En conséquence, tout thread peut modifier l'état du processus global et le corrompre. Au même moment, les points sur lesquels l'état du thread est réputé pouvoir tuer un thread en toute sécurité dépendent de la logique de l'application et ne sont pas connus ni pour le système d'exploitation, ni pour l'exécution du langage de programmation. Par conséquent, terminer les threads au moment arbitraire signifie le tuer à un point arbitraire de son chemin d'exécution et peut facilement entraîner la corruption des données à l'échelle du processus, la mémoire et les fuites, les fuites de threads et les spinlocks ainsi que d'autres primitives de synchronisation intra-processus laissées dans le processus. état fermé empêchant les autres threads de progresser.

Pour cette raison, l’approche commune consiste à obliger les développeurs à implémenter une terminaison de thread synchrone ou coopérative, dans laquelle un thread peut demander une autre terminaison de thread et un autre thread à un point bien défini pouvant vérifier cette requête et démarrer la procédure d'arrêt à partir de l'état bien défini. avec la libération de toutes les ressources du système global et des ressources du processus local de manière sûre et cohérente.

8
ZarathustrA

Astuces pour utiliser une fonction dépendante du système d'exploitation pour terminer le thread C++:

  1. std::thread::native_handle() seul peut obtenir le type de descripteur natif valide du thread avant d’appeler join() ou detach(). Après cela, native_handle() retourne 0 - pthread_cancel() retournera.

  2. Pour appeler efficacement la fonction de terminaison de thread native (par exemple, pthread_cancel), vous devez enregistrer le descripteur natif avant d'appeler std::thread::join() ou std::thread::detach(). Ainsi, votre terminateur natif dispose toujours d'un descripteur natif valide.

Plus d'explications s'il vous plaît se référer à: http://bo-yang.github.io/2017/11/19/cpp-kill-detached-thread .

7
boyang

Je suppose que le fil qui doit être éliminé se trouve soit dans un mode d'attente quelconque, soit dans un travail difficile. Je suggérerais d'utiliser une méthode "naïve".

Définir un booléen global:

std::atomic_bool stop_thread_1 = false;

Placez le code suivant (ou similaire) en plusieurs points clés, de manière à ce que toutes les fonctions de la pile d'appels soient renvoyées jusqu'à la fin naturelle du thread:

if (stop_thread_1)
    return;

Ensuite, pour arrêter le thread d'un autre thread (principal):

stop_thread_1 = true;
thread1.join ();
stop_thread_1 = false; //(for next time. this can be when starting the thread instead)
1
Doron Ben-Ari