web-dev-qa-db-fra.com

Comment retourner une valeur de thread en C

Je suis nouveau sur C et aimerais jouer un peu avec les discussions. Je voudrais renvoyer une valeur d'un fil en utilisant pthread_exit()

Mon code est le suivant:

#include <pthread.h>
#include <stdio.h>

void *myThread()
{
   int ret = 42;
   pthread_exit(&ret);
}

int main()
{
   pthread_t tid;
   void *status;

   pthread_create(&tid, NULL, myThread, NULL);
   pthread_join(tid, &status);

   printf("%d\n",*(int*)status);   

   return 0;
}

Je m'attendrais à la sortie du programme "42\n", mais elle génère un nombre aléatoire. Comment puis-je imprimer la valeur renvoyée?

EDIT: .__ Selon les premières réponses, le problème est que je renvoie le pointeur sur la variable locale. Quelle est la meilleure pratique pour renvoyer/stocker les variables de plusieurs threads? Une table de hachage globale?

Merci d'avance

43
Petr Peller

Vous retournez l'adresse d'une variable locale, qui n'existe plus à la fermeture de la fonction de thread. Dans tous les cas, pourquoi appeler pthread_exit? pourquoi ne pas simplement renvoyer une valeur de la fonction thread?

void *myThread()
{
   return (void *) 42;
}

et ensuite en principal:

printf("%d\n",(int)status);   

Si vous devez renvoyer une valeur compliquée telle qu'une structure, il est probablement plus facile de l'allouer dynamiquement via malloc () et de renvoyer un pointeur. Bien entendu, le code qui a initié le thread sera alors responsable de la libération de la mémoire.

41
anon

Vous avez renvoyé un pointeur sur une variable locale. C'est mauvais même si les discussions ne sont pas impliquées.

La façon habituelle de faire cela, quand le thread qui commence est le même qui se joint, serait de passer un pointeur sur un int, à un emplacement géré par l'appelant, en tant que 4ème paramètre de pthread_create. Cela devient alors le (seul) paramètre du point d'entrée du thread. Vous pouvez (si vous le souhaitez) utiliser la valeur de sortie du thread pour indiquer le succès:

#include <pthread.h>
#include <stdio.h>

int something_worked(void) {
    /* thread operation might fail, so here's a silly example */
    void *p = malloc(10);
    free(p);
    return p ? 1 : 0;
}

void *myThread(void *result)
{
   if (something_worked()) {
       *((int*)result) = 42;
       pthread_exit(result);
   } else {
       pthread_exit(0);
   }
}

int main()
{
   pthread_t tid;
   void *status = 0;
   int result;

   pthread_create(&tid, NULL, myThread, &result);
   pthread_join(tid, &status);

   if (status != 0) {
       printf("%d\n",result);
   } else {
       printf("thread failed\n");
   }

   return 0;
}

Si vous devez absolument utiliser la valeur de sortie du thread pour une structure, vous devrez l'allouer de manière dynamique (et vous assurer que celui qui rejoint le thread la libère). Ce n'est pas idéal, cependant.

25
Steve Jessop

Voici une solution correcte. Dans ce cas, tdata est alloué dans le thread principal et le thread dispose d'un espace pour placer son résultat.

#include <pthread.h>
#include <stdio.h>

typedef struct thread_data {
   int a;
   int b;
   int result;

} thread_data;

void *myThread(void *arg)
{
   thread_data *tdata=(thread_data *)arg;

   int a=tdata->a;
   int b=tdata->b;
   int result=a+b;

   tdata->result=result;
   pthread_exit(NULL);
}

int main()
{
   pthread_t tid;
   thread_data tdata;

   tdata.a=10;
   tdata.b=32;

   pthread_create(&tid, NULL, myThread, (void *)&tdata);
   pthread_join(tid, NULL);

   printf("%d + %d = %d\n", tdata.a, tdata.b, tdata.result);   

   return 0;
}
18
salsaman

Je pense que vous devez stocker le nombre sur le tas. La variable int ret était sur la pile et a été détruite à la fin de l'exécution de la fonction myThread.

void *myThread()
{
       int *ret = malloc(sizeof(int));
       if (ret == NULL) {
           // ...
       }
       *ret = 42;
       pthread_exit(ret);
}

N'oubliez pas de free quand vous n'en avez pas besoin :)

Une autre solution consiste à renvoyer le nombre en tant que valeur du pointeur, comme le suggère Neil Butterworth.

3
Messa
#include<stdio.h>
#include<pthread.h>
void* myprint(void *x)
{
 int k = *((int *)x);
 printf("\n Thread created.. value of k [%d]\n",k);
 //k =11;
 pthread_exit((void *)k);

}
int main()
{
 pthread_t th1;
 int x =5;
 int *y;
 pthread_create(&th1,NULL,myprint,(void*)&x);
 pthread_join(th1,(void*)&y);
 printf("\n Exit value is [%d]\n",y);
}  
2
Abhishek

Vous retournez une référence à ret qui est une variable de la pile.

2
Maurits Rijk

Question: Quelle est la meilleure pratique pour renvoyer/stocker les variables de plusieurs threads? Une table de hachage globale?

Cela dépend totalement de ce que vous voulez retourner et comment vous l'utiliseriez? Si vous voulez renvoyer uniquement le statut du thread (par exemple, si le thread a terminé ce qu'il comptait faire), utilisez simplement pthread_exit ou utilisez une instruction return pour renvoyer la valeur à partir de la fonction de thread. 

Toutefois, si vous souhaitez des informations supplémentaires qui seront utilisées pour un traitement ultérieur, vous pouvez utiliser la structure de données globale. Mais dans ce cas, vous devez gérer les problèmes de simultanéité à l'aide de primitives de synchronisation appropriées. Vous pouvez également allouer de la mémoire dynamique (de préférence pour la structure dans laquelle vous souhaitez stocker les données) et l'envoyer via pthread_exit. Une fois le thread joint, vous la mettez à jour dans une autre structure globale. De cette manière, seul le thread principal mettra à jour la structure globale et les problèmes de simultanéité seront résolus. Cependant, vous devez vous assurer de libérer toute la mémoire allouée par différents threads.

1
Jay

si vous ne souhaitez pas renvoyer d’adresses et n’avez qu’une seule variable, par exemple. une valeur entière à renvoyer, vous pouvez même la transtyper dans (void *) avant de la transmettre, puis lorsque vous la collectez dans la fenêtre principale, à nouveau la transtyper dans (int). Vous avez la valeur sans jeter de vilains avertissements.

0
Aditya