c casting void-pointers

¿Cómo lanzar un entero para anular el puntero?



casting void-pointers (4)

Esta es una buena manera de pasar enteros a nuevos pthreads, si eso es lo que necesita. Solo necesitas suprimir la advertencia, y esto lo harás:

#include <stdint.h> void *threadfunc(void *param) { int id = (intptr_t) param; ... } int i, r; r = pthread_create(&thread, NULL, threadfunc, (void *) (intptr_t) i);

Discusión

Esto puede ofender sus sensibilidades, pero es muy corto y no tiene condiciones de carrera (como lo haría si usara &i ). No tiene sentido escribir unas pocas docenas de líneas de código adicional solo para obtener un montón de hilos numerados.

Carreras de datos

Aquí hay una mala versión con una carrera de datos:

#include <pthread.h> #include <stdio.h> #define N 10 void *thread_func(void *arg) { int *ptr = arg; // Has *ptr changed by the time we get here? Maybe! printf("Arg = %d/n", *ptr); return NULL; } int main() { int i; pthread_t threads[N]; for (i = 0; i < N; i++) { // NO NO NO NO this is bad! pthread_create(&threads[i], NULL, thread_func, &i); } for (i = 0; i < N; i++) { pthread_join(threads[i], NULL); } return 0; }

Ahora, ¿qué pasa cuando lo ejecuto con el desinfectante de hilos?

(Además, mira cómo se imprime "5" dos veces ...)

================== WARNING: ThreadSanitizer: data race (pid=20494) Read of size 4 at 0x7ffc95a834ec by thread T1: #0 thread_func /home/depp/test.c:9 (a.out+0x000000000a8c) #1 <null> <null> (libtsan.so.0+0x000000023519) Previous write of size 4 at 0x7ffc95a834ec by main thread: #0 main /home/depp/test.c:17 (a.out+0x000000000b3a) Location is stack of main thread. Thread T1 (tid=20496, running) created by main thread at: #0 pthread_create <null> (libtsan.so.0+0x0000000273d4) #1 main /home/depp/test.c:18 (a.out+0x000000000b1c) SUMMARY: ThreadSanitizer: data race /home/depp/test.c:9 thread_func ================== Arg = 1 Arg = 2 Arg = 3 Arg = 4 Arg = 5 Arg = 6 Arg = 7 Arg = 8 Arg = 9 Arg = 5 ThreadSanitizer: reported 1 warnings

Mientras trabajo con Threads en C, me enfrento a la advertencia.

"advertencia: convertir a puntero desde un entero de diferente tamaño"

El código es el siguiente

#include<stdio.h> #include<sys/types.h> #include<stdlib.h> #include<pthread.h> void *print(void *id) { int a=10; printf("My thread id is %ld/n",pthread_self()); printf("Thread %d is executing/n",id); return (void *) 42; } int main() { pthread_t th[5]; int t; int i; int status; void *ret; for(i=0;i<5;i++) { status=pthread_create(&th[i],NULL,print,(void *)i); //Getting warning at this line if(status) { printf("Error creating threads/n"); exit(0); } pthread_join(th[i],&ret); printf("--->%d/n",(int *)ret); } pthread_exit(NULL); }

¿Alguien puede explicar cómo pasar un entero a una función que recibe (void *) como parámetro?


Puedes hacer algo como esto:

#include <stdio.h> #include <sys/types.h> #include <stdlib.h> #include <pthread.h> struct th { pthread_t thread; int id; int ret; }; void *print(void *id) { int a=10; struct th *self = (struct th *) id; printf("My thread id is %ld/n",pthread_self()); printf("Thread %d is executing/n",self->id); self->ret = random(); return; } int main(void) { struct th th[5]; int t; int i; int status; void *ret; for(i=0;i<5;i++) { th[i].id = i; status=pthread_create(&th[i].thread,NULL,print,&th[i]); //Getting warning at this line if(status) { printf("Error creating threads/n"); exit(0); } } for (i=0;i<5;i++) { pthread_join(th[i].thread,&ret); printf("%d--->%d/n",th[i].id,th[i].ret); } pthread_exit(NULL); }

saldrá:

My thread id is 4496162816 My thread id is 4497870848 My thread id is 4498944000 My thread id is 4498407424 Thread 0 is executing Thread 1 is executing My thread id is 4499480576 Thread 3 is executing Thread 2 is executing 0--->1804289383 Thread 4 is executing 1--->846930886 2--->1714636915 3--->1681692777 4--->1957747793

pasar un puntero único a cada subproceso no se ejecutará, y puede obtener / guardar cualquier tipo de información en la estructura


cambio:

status=pthread_create(&th[i],NULL,print,(void *)i);

a:

status=pthread_create(&th[i],NULL,print,(reinterpret_cast<void*>(i));

El reinterpret_cast hace que el int sea del tamaño de un puntero y la advertencia se detendrá. Básicamente es una mejor versión de (void *) i.


puede pasar el valor int como puntero de vacío como (void *)&n donde n es entero, y en la función aceptar puntero de void como parámetro como void foo(void *n); y finalmente, dentro de la función, convertir el puntero del vacío en int, int num = *(int *)n; . De esta manera no recibirá ninguna advertencia.