GNU/Linux >> Tutoriels Linux >  >> Linux

Est-il sûr de bifurquer à partir d'un thread?

Le problème est que fork() ne copie que le thread appelant, et tous les mutex contenus dans les threads enfants seront définitivement verrouillés dans l'enfant forké. La solution pthread était le pthread_atfork() manutentionnaires. L'idée était que vous pouvez enregistrer 3 gestionnaires :un préfork, un gestionnaire parent et un gestionnaire enfant. Quand fork() se produit prefork est appelé avant fork et devrait obtenir tous les mutex d'application. Le parent et l'enfant doivent libérer tous les mutex dans les processus parent et enfant respectivement.

Ce n'est pourtant pas la fin de l'histoire ! Les bibliothèques appellent pthread_atfork pour enregistrer des gestionnaires pour les mutex spécifiques à la bibliothèque, par exemple Libc le fait. C'est une bonne chose :l'application ne peut pas connaître les mutex détenus par les bibliothèques tierces, donc chaque bibliothèque doit appeler pthread_atfork pour s'assurer que ses propres mutex sont nettoyés en cas de fork() .

Le problème est que la commande pthread_atfork les gestionnaires sont appelés pour des bibliothèques non liées n'est pas défini (cela dépend de l'ordre dans lequel les bibliothèques sont chargées par le programme). Cela signifie donc que techniquement, un blocage peut se produire à l'intérieur d'un gestionnaire de préfork en raison d'une condition de concurrence.

Par exemple, considérez cette séquence :

  1. Le thread T1 appelle fork()
  2. les gestionnaires de préfork libc sont appelés dans T1 (par exemple, T1 détient maintenant tous les verrous libc)
  3. Ensuite, dans Thread T2, une bibliothèque tierce A acquiert son propre mutex AM, puis effectue un appel libc qui nécessite un mutex. Cela bloque, car les mutex libc sont détenus par T1.
  4. Le thread T1 exécute le gestionnaire de préfork pour la bibliothèque A, qui bloque l'attente d'obtenir AM, qui est détenu par T2.

Il y a votre blocage et ce n'est pas lié à vos propres mutex ou code.

Cela s'est produit sur un projet sur lequel j'ai déjà travaillé. Le conseil que j'avais trouvé à l'époque était de choisir fourche ou fils mais pas les deux. Mais pour certaines applications, ce n'est probablement pas pratique.


Il est sûr de bifurquer dans un programme multithread tant que vous êtes très attention au code entre fork et exec. Vous ne pouvez effectuer que des appels système réentrants (c'est-à-dire asynchrones sécurisés) dans cette plage. En théorie, vous n'êtes pas autorisé à malloc ou à libérer là-bas, bien qu'en pratique l'allocateur Linux par défaut soit sûr, et les bibliothèques Linux en sont venues à s'y fier. Le résultat final est que vous devez utiliser l'allocateur par défaut.


Linux
  1. Obtenir le chemin complet depuis le script Bash ?

  2. Exécuter le programme à partir d'un programme C

  3. Accéder au thread local à partir d'un autre thread

  4. Ouvrir Vim depuis un script shell Bash

  5. Bash :exécuter des commandes depuis un chroot et changer d'utilisateur

Comment accéder au shell ou exécuter des commandes externes depuis Vim

Protégez les serveurs CentOS 6 contre une nouvelle vulnérabilité OpenSSL

Mettre à niveau Ubuntu dans Docker de 14.04 à 16.04 à l'aide de Do-release-upgrade ?

Comment utiliser le webmail depuis cPanel

Comment puis-je obtenir des informations sur le conteneur Docker Linux à partir du conteneur lui-même ?

Créer des liens symboliques NTFS à partir de Linux