¿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.