2010-02-12 37 views
40

Soy nuevo en C y me gustaría jugar un poco con los hilos. Me gustaría volver algún valor de un hilo usando pthread_exit()Cómo devolver un valor desde el hilo en C

Mi código es el siguiente:

#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; 
} 

Yo esperaría que la salida del programa "42 \ n", pero da salida a un número aleatorio. ¿Cómo puedo imprimir el valor devuelto?

EDIT: Según las primeras respuestas, el problema es que estoy devolviendo el puntero a la variable local. ¿Cuál es la mejor práctica de devolver/almacenar variables de múltiples hilos? Una tabla hash global?

Gracias de antemano

+1

En respuesta a la edición: Me tienden a utilizar una matriz si necesitaba previstas múltiples hilos cada uno con un lugar para escribir sus resultados. Si no sabes de antemano un límite superior en la cantidad de hilos que vas a crear, normalmente lo consideraría un problema. Pero, en general, cualquier estructura está bien siempre y cuando quien inicia el hilo pueda asegurar que haya un lugar para que el hilo almacene su resultado; el hilo se le dice dónde almacenarlo; y quien se una al hilo puede recuperar el resultado y, si es necesario, liberarlo. Si el hilo sale con el mismo valor que se pasó como parámetro, eso puede ayudar. –

Respuesta

34

Está devolviendo la dirección de una variable local, que ya no existe cuando sale la función de subproceso. En cualquier caso, ¿por qué llamar a pthread_exit? ¿por qué no simplemente devuelve un valor de la función de hilo?

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

y luego en el principal:

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

Si tiene que devolver un valor complicada tal estructura, es probablemente más fácil de asignar de forma dinámica a través de malloc() y devolver un puntero. Por supuesto, el código que inició el hilo será responsable de liberar la memoria.

+1

Si realmente quiere decir "por qué no", entonces la razón por la que no es que la conversión 42 a un tipo de puntero es un comportamiento indefinido. Por supuesto, si hace algo malo, entonces es uno de esos momentos "es una implementación C, Jim, pero no como lo conocemos". –

+0

@Steve Hay momentos en los que arriesgaré un poco de UB, esta es una de ellas, las alternativas son muy complicadas. –

+0

Yo también, pero yo no pondría la etiqueta "portátil en cualquier parte" en la caja. –

3

Yo creo que hay que guardar el número en el montón. La variable int ret estaba en la pila y se destruyó al final de la ejecución de la función myThread.

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

No se olvide de free que cuando no lo necesita :)

Otra solución es devolver el número como valor del puntero, como Neil Butterworth sugiere.

+0

Es estúpido que pthread_exit solo acepte un puntero como parámetro :( –

+3

No es "estúpido", es una limitación del sistema de tipo C. Para devolver un parámetro de tipo arbitrario a través del sistema pthreads, o necesita un estilo Python sistema de objetos, donde las variables no tienen tipos, solo los valores, o si no necesitas mucha tecnología de plantillas C++. De la misma manera, solo puedes devolver 'void *' desde el punto de entrada del hilo, no puedes devuelve (por ejemplo) un doble. –

+1

También no olvides que para comprobar que 'malloc' funcionó :-) –

25

Ha devuelto un puntero a una variable local. Eso es malo incluso si los hilos no están involucrados.

La forma habitual de hacerlo, cuando el hilo que se inicia es el mismo que se une, sería pasar un puntero a un int, en una ubicación administrada por el llamador, como el 4º parámetro de pthread_create. Esto se convierte entonces en el (único) parámetro para el punto de entrada del hilo. Se puede (si lo desea) utilizar el valor de salida de rosca para indicar el éxito:

#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 es absolutamente necesario utilizar el valor de salida de rosca para una estructura, entonces usted tendrá que asignar dinámicamente (y asegurarse que quien se una al hilo lo libera). Eso no es ideal, sin embargo.

+2

Acabo de descubrir esto, pero de acuerdo con http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_exit .html no necesita usar pthread_exit en su llamada de función para el hilo. "El mecanismo normal por el que termina un hilo es regresar de la rutina que se especificó en la llamada pthread_create() que lo inició. La función pthread_exit() proporciona la capacidad para que un hilo termine sin requerir un retorno de la rutina de inicio de ese hilo, proporcionando de ese modo una función análoga a exit(). " pthread_exit debe usarse para la terminación anticipada. –

+1

'printf (" thread failed \ n ");' - En su lugar, imprimiría el error a 'stderr' utilizando' fprintf'. –

2

Usted está regresando una referencia a ret que es una variable en la pila.

1

Pregunta: ¿Cuál es la mejor práctica de devolver/almacenar variables de múltiples hilos? Una tabla hash global?

Esto depende totalmente de lo que desea devolver y cómo lo usaría?Si desea devolver solo el estado del hilo (por ejemplo, si el hilo completó lo que pretendía hacer), simplemente use pthread_exit o use una declaración return para devolver el valor de la función hilo.

Pero, si desea obtener más información que se utilizará para un procesamiento posterior, puede utilizar la estructura de datos global. Pero, en ese caso, necesita manejar problemas de concurrencia mediante el uso de primitivas de sincronización apropiadas. O bien, puede asignar memoria dinámica (preferiblemente para la estructura en la que desea almacenar los datos) y enviarla a través de pthread_exit y una vez que el hilo se una, la actualice en otra estructura global. De esta forma, solo un hilo principal actualizará la estructura global y se resolverán los problemas de concurrencia. Sin embargo, debe asegurarse de liberar toda la memoria asignada por diferentes subprocesos.

0

si no se siente cómodo con el envío de direcciones y tiene una sola variable, por ejemplo. un valor entero para devolver, incluso puede encasillarlo en (void *) antes de pasarlo, y luego cuando lo recopile en el principal, vuelva a encasillarlo en (int). Tienes el valor sin lanzar feos avisos.

11

Aquí hay una solución correcta. En este caso, tdata se asigna en el hilo principal, y hay un espacio para que el hilo coloque su resultado.

#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; 
} 
+0

Este es el ejemplo más limpio aquí. Estoy sorprendido de que no esté más altamente votado. En particular, muestra que la gestión del almacenamiento en el nivel de llamada es lo correcto, y también que el puntero puede usarse para pasar estructuras más complejas, tanto dentro como fuera. – Floris

2
#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); 
} 
+0

Devuelve el valor de una variable local de la función de subproceso. sin usar la variable global. – Abhishek

Cuestiones relacionadas