2011-05-04 21 views
7

Las funciones pthread toman un argumento void *. ¿Cómo se puede enviar una estructura simple, no un puntero?Pasar datos normales a pthread void *

Quiero enviar una estructura no puntero a una función pthread.

También quiero enviar un puntero a la función void *, ¿cómo se hace esto? ¿Se puede enviar cualquier puntero a la función void *?

+0

Para pasar una estructura, necesita pasar la dirección de la misma (que la convierte en un puntero). Sin embargo, debe asegurarse de que el objeto no se destruya (ya que el hilo tendrá una referencia). Sí, puede pasar cualquier puntero a un vacío * – forsvarir

+0

No puede (AFAIK). ¿Qué hay de malo con un puntero a una estructura basada en montón? –

+0

¿No puedo simplemente enviar la estructura como esta y la estructura al (vacío *) – jarryd

Respuesta

7

No es posible; tienes que enviar un puntero Sin embargo, un void * puede apuntar a cualquier cosa. Si su variable struct se llama foo, simplemente puede pasarla como (void *) &foo, y dentro de la función, puede convertirla de nuevo en, por ejemplo, a struct Foo con struct Foo * fooPtr = (struct Foo *) param; o struct Foo foo = *((struct Foo *) param);.

Edit: Como @forsvarir mencionado en el comentario, foo no deben ser una variable local (a menos que la función de invocación espera a que el hilo para completar). Ver la publicación de @Gavin Lock.

3

Como ya se mencionó, debe pasar un puntero. Piense en void * como un puntero sin tipo, por lo que debe devolverlo al tipo correcto dentro de la función de subprocesos. (ver la respuesta de Aasmund)

Como forsvarir menciona, TIENES que asegurarte de que la estructura apuntada no se destruye antes de que el hilo la use, la forma más segura de hacerlo es volver a la estructura en el montón y pasar su dirección y propiedad de la función hilo.

Lo que quiero decir por "pasar la propiedad" es que la función que las noticias de la estructura no debe eliminarlo, y la función del hilo deben eliminar la estructura vez que se hace con ella.

+0

+1 para los puntos sobre la propiedad. –

7

Sobre la base de sus comentarios que hay que hacer algo como esto ...

En su código principal:

void PassSomeStuff(struct TheStruct myStruct) { 
    struct TheStruct *pStruct = malloc(sizeof(struct TheStruct)); 
    memcpy(pStruct, &myStruct, sizeof(struct TheStruct)); 

    /* Start the watchdog thread passing in the structure */ 
    pthread_create(/* other args */, &myWatchDogThreadFunc, pStruct); */ 
} 

En su flujo watchdog:

void *myWatchDogThreadFunc(void *pArgs) { 
    struct TheStruct *pStruct = (struct TheStruct *)pArgs; 

    /* use the struct */ 

    /* Pass Ownership to the navigation thread*/ 
    /* Start the navigation thread passing in the structure */ 
    pthread_create(/* other args */, &myNavigationThreadFunc, pStruct); 
} 

En el hilo de navegación :

void *myNavigationThreadFunc(void *pArgs) { 
    struct TheStruct *pStruct = (struct TheStruct *)pArgs; 
    /* use the struct */ 

    /* cleanup */ 
    free(pStruct); /* or pass it to somebody else... */ 
} 

No se puede hacer:

void PassSomeStuff(struct TheStruct myStruct) { 
    pthread_create(/* other args */, &myStruct); 
} 

Debido myStruct obtendrá limpiado ... PassSomeStuff cuando regresa. Tomando la dirección (obteniendo un puntero), no copia el objeto.

Nota:

  • cualquiera de sus hilos puede limpiar la estructura llamando gratis, siempre y cuando usted puede estar seguro de que todos los hilos terminado con él.
  • TODOS los hilos (principal, watchdog, navegación) hacen referencia a la misma instancia de la estructura (por lo que si cambian su contenido, es posible que deba protegerlo con el bloqueo). Si este no es el efecto deseado, entonces necesitaría crear (malloc) una nueva copia de la estructura en cada paso, de modo que cada hilo tenga su propia copia de los valores.
+0

+1 para escribir un ejemplo de código. – JeremyP

+0

Voy a pasar un puntero desde el principio. malloc antes de enviarlo al perro guardián (que también es un hilo) y luego el perro guardián debe pasarlo a un hilo de navegación gps. ¿Puedo pasar el puntero por el vacío * pthread args entonces? – jarryd

+0

@ Helium3: actualicé mi publicación para reflejar lo que creo que está diciendo, incluidas algunas notas en la parte inferior. La respuesta corta es sí (asumiendo que te he entendido bien). – forsvarir

1

Esto no es una respuesta completa, sino más bien una solución alternativa a las advertencias que otros han ofrecido para asegurarse de que la estructura aún exista cuando el nuevo hilo la obtenga. Ciertamente puede usar malloc para obtenerlo, y darle al nuevo hilo la responsabilidad de free ing it. En muchos sentidos esto parece ser la forma más simple y económica (no se requiere sincronización), pero la sincronización está realmente oculta dentro de malloc y free, y podría ser ligeramente costosa, especialmente dado que la mayoría de los asignadores orientados a hilos (p.ej. ptmalloc y tcmalloc) incurren en cuesta cuando el hilo que libera la memoria no es lo mismo que el hilo que lo asignó.

Un enfoque diferente que puede utilizar es poner una barrera pthread dentro de su estructura init, y esperar en él:

pthread_barrier_init(&init_struct.barrier, 0, 2); 
pthread_create(&td, 0, start_func, &init_struct); 
pthread_barrier_wait(&init_struct.barrier); 

y tienen la función inicial de la rosca también llamada pthread_barrier_wait(arg->barrier); después de copiar la estructura de su propia automática almacenamiento.