Plusieurs arguments pour la fonction appelée par pthread_create ()?

93

J'ai besoin de passer plusieurs arguments à une fonction que je voudrais appeler sur un thread séparé. J'ai lu que la manière typique de le faire est de définir une structure, de lui transmettre un pointeur et de la déréférencer pour les arguments. Cependant, je ne parviens pas à faire fonctionner cela:

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

struct arg_struct {
    int arg1;
    int arg2;
};

void *print_the_arguments(void *arguments)
{
    struct arg_struct *args = (struct arg_struct *)args;
    printf("%d\n", args -> arg1);
    printf("%d\n", args -> arg2);
    pthread_exit(NULL);
    return NULL;
}

int main()
{
    pthread_t some_thread;
    struct arg_struct args;
    args.arg1 = 5;
    args.arg2 = 7;

    if (pthread_create(&some_thread, NULL, &print_the_arguments, (void *)&args) != 0) {
        printf("Uh-oh!\n");
        return -1;
    }

    return pthread_join(some_thread, NULL); /* Wait until thread is finished */
}

Le résultat pour cela devrait être:

5
7

Mais quand je le lance, j'obtiens:

141921115
-1947974263

Quelqu'un sait ce que je fais de mal?

Michael
la source
2
essayez de l'allouer sur le tas?
Carson Myers
1
@Carson Pourquoi cela devrait-il faire une différence?
sigjuice
5
Votre structure doit vivre au moins aussi longtemps que votre fil. Si vous créez un thread et que vous revenez de la fonction qui a appelé pthread_create (), la structure allouée sur la pile peut être écrasée par d'autres données et peut causer des problèmes dans votre fonction de thread. Dans cet exemple, ce n'est pas un problème, car le thread de création attend que le thread de travail se termine avant de revenir.
Commodore Jaeger
@Commodore Jaeger Oh! Merci, c'est le problème que j'avais avec l'autre avec qui je travaillais. Je l'ai corrigé en l'allouant sur le tas en utilisant malloc (), comme l'a dit Carson. Cela a beaucoup plus de sens maintenant.
Michael

Réponses:

77

Parce que tu dis

struct arg_struct *args = (struct arg_struct *)args;

au lieu de

struct arg_struct *args = arguments;

Sigjuice
la source
5
@sigjuice, ça ne marche pas pour moi. Je vois une erreur de compilation: conversion invalide de «void *» en «arg_struct *».
Neshta
20

utilisation

struct arg_struct *args = (struct arg_struct *)arguments;

au lieu de

struct arg_struct *args = (struct arg_struct *)args;
Akash Agrawal
la source
4

main()a ses propres variables de thread et de pile. soit allouer de la mémoire pour 'args' dans le tas, soit le rendre global:

struct arg_struct {
    int arg1;
    int arg2;
}args;

//declares args as global out of main()

Alors bien sûr changez les références de args->arg1à args.arg1etc.

Plamen Panov
la source
2

Utilisation:

struct arg_struct *args = malloc(sizeof(struct arg_struct));

Et passez ces arguments comme ceci:

pthread_create(&tr, NULL, print_the_arguments, (void *)args);

N'oubliez pas les arguments gratuits! ;)

Elham
la source
1

Les arguments de print_the_arguments sont des arguments, vous devez donc utiliser:

struct arg_struct *args = (struct arg_struct *)arguments. 
Pierre Carton
la source
1
struct arg_struct *args = (struct arg_struct *)args;

-> cette affectation est erronée, je veux dire que l'argument variable doit être utilisé dans ce contexte. À votre santé!!!

Jashmikant
la source
1

Dans la création de thread de ce code, l'adresse d'un pointeur de fonction est passée. L'original pthread_create(&some_thread, NULL, &print_the_arguments, (void *)&args) != 0

Il devrait se lire comme pthread_create(&some_thread, NULL, print_the_arguments, (void *) &args)

Un bon moyen de se souvenir est que tous les arguments de cette fonction doivent être des adresses.

some_threadest déclaré statiquement, l'adresse est donc envoyée correctement en utilisant &.

Je créerais une pthread_attr_tvariable, puis l'utiliserais pthread_attr_init()et transmettrais l'adresse de cette variable. Mais, passer un NULLpointeur est également valide.

Le &devant de l'étiquette de fonction est ce qui cause le problème ici. Le libellé utilisé est déjà une void*fonction vers une fonction, donc seul le libellé est nécessaire.

Dire != 0avec l'argument final semble provoquer un comportement indéterminé. L'ajout de cela signifie qu'un booléen est passé au lieu d'une référence.

La réponse d'Akash Agrawal fait également partie de la solution au problème de ce code.

Rayshaun Preston
la source
1

J'ai la même question que l'affiche originale, Michael.

Cependant, j'ai essayé d'appliquer les réponses soumises pour le code d'origine sans succès

Après quelques essais et erreurs, voici ma version du code qui fonctionne (ou du moins fonctionne pour moi!). Et si vous regardez de près, vous remarquerez que c'est différent des solutions précédentes publiées.

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

struct arg_struct
{
   int arg1;
   int arg2;
} *args;

void *print_the_arguments(void *arguments)
{
   struct arg_struct *args = arguments;
   printf("Thread\n");
   printf("%d\n", args->arg1);
   printf("%d\n", args->arg2);
   pthread_exit(NULL);
   return NULL;
}

int main()
{
   pthread_t some_thread;
   args = malloc(sizeof(struct arg_struct) * 1);

   args->arg1 = 5;
   args->arg2 = 7;

   printf("Before\n");
   printf("%d\n", args->arg1);
   printf("%d\n", args->arg2);
   printf("\n");


   if (pthread_create(&some_thread, NULL, &print_the_arguments, args) != 0)
   {
      printf("Uh-oh!\n");
      return -1;
   }

   return pthread_join(some_thread, NULL); /* Wait until thread is finished */
}
VeeDub
la source