pthread exit vs retour

j'ai une fonction pthread runner articulable définie comme suit:

void *sumOfProducts(void *param)
{
...
pthread_exit(0);
}

ce fil est supposé joindre le fil principal.

chaque fois que J'ai passé mon programme par Valgrind, J'ai eu le fuites suivantes :

LEAK SUMMARY:
   definitely lost: 0 bytes in 0 blocks
   indirectly lost: 0 bytes in 0 blocks
     possibly lost: 0 bytes in 0 blocks
   still reachable: 968 bytes in 5 blocks
        suppressed: 0 bytes in 0 blocks

ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 15 from 10)

j'ai vérifié la page de manuel pour pthreads qui a dit:

  The new thread terminates in one of the following ways:

   * It  calls  pthread_exit(3),  specifying  an exit status value that is
     available  to  another  thread  in  the  same  process   that   calls
     pthread_join(3).

   * It  returns  from  start_routine().   This  is  equivalent to calling
     pthread_exit(3) with the value supplied in the return statement.

   * It is canceled (see pthread_cancel(3)).

   * Any of the threads in the process calls exit(3), or the  main  thread
     performs  a  return  from main().  This causes the termination of all
     threads in the process.

miraculeusement, quand j'ai remplacé le pthread_exit () par un retour déclaration, les fuites ont disparu .

return(NULL);

ma question actuelle est en trois volets:

  1. Quelqu'un peut-il expliquer pourquoi la déclaration de retour n'a donné lieu à aucune fuite?
  2. y a-t-il une différence fondamentale entre les deux énoncés, en ce qui concerne la sortie des fils?
  3. dans l'affirmative, à quel moment l'un devrait-il être préféré à l'autre?
33
demandé sur caf 2010-10-02 10:41:12

5 réponses

le test minimal suivant montre le comportement que vous décrivez:

#include <pthread.h>
#include <unistd.h>

void *app1(void *x)
{
    sleep(1);
    pthread_exit(0);
}

int main()
{
    pthread_t t1;

    pthread_create(&t1, NULL, app1, NULL);
    pthread_join(t1, NULL);

    return 0;
}

valgrind --leak-check=full --show-reachable=yes affiche 5 blocs alloués à partir de fonctions appelées par pthread_exit() qui n'est pas créé mais est toujours accessible à la sortie du processus. Si le pthread_exit(0); est remplacé par return 0; , les 5 blocs ne sont pas attribués.

cependant, si vous testez la création et l'assemblage d'un grand nombre de threads, vous trouverez que la quantité de mémoire libre en usage à la sortie est-ce que n'augmente pas . Ceci, et le fait qu'il est toujours accessible, indique que vous voyez juste une bizarrerie de l'implémentation glibc. Plusieurs fonctions glibc allouent de la mémoire avec malloc() la première fois qu'ils sont appelés, qu'ils gardent alloué pour le reste de la durée de vie du processus. glibc ne prend pas la peine de libérer cette mémoire à la sortie du processus, car il sait que le processus est en train d'être détruit de toute façon - ce serait juste un gaspillage de cycles CPU.

37
répondu caf 2010-10-02 07:03:23

Je ne suis pas sûr que cela vous intéresse toujours, mais je suis en train de déboguer une situation similaire. Les Threads qui utilisent pthread_exit font que valgrind déclare les blocs accessibles. La raison semble être assez bien expliquée ici:

https://bugzilla.redhat.com/show_bug.cgi?id=483821

Essentiellement, il semble pthread_exit provoque un dlopen qui n'est jamais nettoyé explicitement lorsque le processus s'arrête.

11
répondu Steven S 2011-05-10 06:55:46

il semble que l'appel à exit() (et, apparemment, pthread_exit()) laisse les variables allouées automatiquement allouées. Vous devez soit retourner ou jeter afin de se détendre correctement.

Par C++ valgrind fuites possibles sur STL chaîne :

@Klaim: Je ne vois pas où ce document dit que je me trompe, mais si c'est le cas alors c'est mal. Pour citer la norme c++ (§18.3 / 8): "Automatique objets ne sont pas détruit suite à l'appel de exit()." – James McNellis Sep 10 ' 10 at 19: 11

depuis que faire un " return 0 "au lieu de" pthread_exit(0) " semble résoudre votre problème (et le mien.. merci), je suppose que le comportement est similaire entre les deux.

1
répondu Dustin Oprea 2017-05-23 10:30:37

utilisez-vous vraiment C++, par hasard? Pour clarifier - votre fichier source se termine par une extension .c , et vous le compilez avec gcc , pas g++ ?

il semble raisonnablement probable que votre fonction soit en train d'allouer des ressources que vous attendez d'être nettoyées automatiquement lorsque la fonction retourne. Les objets c++ locaux comme std::vector ou std::string font ceci, et leurs destructeurs ne seront probablement pas lancés si vous appelez pthread_exit , mais serait nettoyé si vous venez de retour.

Ma préférence est d'éviter les API de bas niveau telles que pthread_exit , et toujours simplement revenir de la fonction thread, lorsque cela est possible. Ils sont équivalents, sauf que pthread_exit est une construction de contrôle de flux qui contourne le langage que vous utilisez, mais return ne le fait pas.

0
répondu Doug 2010-10-02 06:55:51

j'ai l'expérience que valgrind a des difficultés à suivre le stockage est alloué pour l'état de recrutables threads. (Ceci va dans la même direction que celle indiquée par les FAC.)

Puisqu'il semble que vous retournez toujours une valeur de 0 je suppose que vous avez peut-être besoin de joindre vos fils du point de vue de l'application? Si donc envisager de les lancer détaché dès le début, cela évite l'allocation de la mémoire.

l'inconvénient est que vous avez soit:

  1. pour mettre en œuvre votre propre barrière à la fin de votre main . Si vous connaissez le nombre de fils à l'avance, un répartition statique simple pthread_barrier suffirait.
  2. ou pour sortir de vous main avec pthread_exit tels que vous ne tuer le reste des fils de course qui ne soit pas encore terminé.
0
répondu Jens Gustedt 2010-10-02 07:57:08