¿Múltiples argumentos a la función llamada por pthread_create ()?

94

Necesito pasar varios argumentos a una función a la que me gustaría llamar en un hilo separado. He leído que la forma típica de hacer esto es definir una estructura, pasarle un puntero a la función y eliminar la referencia de los argumentos. Sin embargo, no puedo hacer que esto funcione:

#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 */
}

La salida para esto debería ser:

5
7

Pero cuando lo ejecuto, en realidad obtengo:

141921115
-1947974263

¿Alguien sabe lo que estoy haciendo mal?

Miguel
fuente
2
intente asignarlo en el montón?
Carson Myers
1
@Carson ¿Por qué eso debería marcar la diferencia?
sigjuice
5
Su estructura debe vivir al menos tanto como su hilo. Si está creando un hilo y regresando de la función que llamó pthread_create (), la estructura asignada en la pila puede ser sobrescrita por otros datos y podría causar problemas en su función del hilo. En este ejemplo, eso no es un problema, ya que el hilo de creación espera a que se complete el hilo de trabajo antes de regresar.
Commodore Jaeger
@Comodoro Jaeger ¡Oh! Gracias, ese es el problema que tenía con el otro con el que estaba trabajando. Lo arreglé asignándolo en el montón usando malloc (), como dijo Carson. Eso tiene mucho más sentido ahora.
Michael

Respuestas:

77

Porque tú dices

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

en vez de

struct arg_struct *args = arguments;

sigjuice
fuente
5
@sigjuice, no me funciona. Veo un error de compilación: conversión no válida de 'void *' a 'arg_struct *'.
Neshta
20

utilizar

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

en lugar de

struct arg_struct *args = (struct arg_struct *)args;
Akash Agrawal
fuente
4

main()tiene su propio hilo y variables de pila. asigne memoria para 'args' en el montón o hágalo global:

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

//declares args as global out of main()

Luego, por supuesto, cambie las referencias de args->arg1a, args.arg1etc.

Plamen Panov
fuente
2

Utilizar:

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

Y pase estos argumentos así:

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

¡No olvides los argumentos gratis! ;)

Elham
fuente
1

Los argumentos de print_the_arguments son argumentos, por lo que debes usar:

struct arg_struct *args = (struct arg_struct *)arguments. 
Piedra.Carton
fuente
1
struct arg_struct *args = (struct arg_struct *)args;

-> esta asignación es incorrecta, quiero decir que el argumento de la variable debe usarse en este contexto. ¡¡¡Salud!!!

Jashmikant
fuente
1

En la creación del hilo de este código, se pasa la dirección de un puntero de función. El original pthread_create(&some_thread, NULL, &print_the_arguments, (void *)&args) != 0

Debería leerse como pthread_create(&some_thread, NULL, print_the_arguments, (void *) &args)

Una buena forma de recordar es que todos los argumentos de esta función deben ser direcciones.

some_thread se declara estáticamente, por lo que la dirección se envía correctamente utilizando & .

Crearía una pthread_attr_tvariable, luego la usaría pthread_attr_init()y pasaría la dirección de esa variable. Pero, pasando unNULL puntero también es válido.

El &frente de la etiqueta de la función es lo que está causando el problema aquí. La etiqueta utilizada ya es unavoid* una función, por lo que solo es necesaria la etiqueta.

Decir != 0con el argumento final parecería provocar un comportamiento indeterminado. Agregar esto significa que se pasa un booleano en lugar de una referencia.

La respuesta de Akash Agrawal también es parte de la solución al problema de este código.

Rayshaun Preston
fuente
1

Tengo la misma pregunta que el póster original, Michael.

Sin embargo, intenté aplicar las respuestas enviadas para el código original sin éxito

Después de algunas pruebas y errores, aquí está mi versión del código que funciona (¡o al menos funciona para mí!). Y si observa de cerca, notará que es diferente a las soluciones publicadas anteriormente.

#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
fuente