Как отличить целое число от указателя void?
Во время работы с Threads в C я сталкиваюсь с предупреждением
"предупреждение: отбрасывать указатель из целого разного размера"
Код выглядит следующим образом
#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);
}
Может ли кто-нибудь объяснить, как передать целое число функции, которая принимает (void *) в качестве параметра?
Ответы
Ответ 1
Это прекрасный способ передать целые числа в новые pthreads, если это то, что вам нужно. Вам просто нужно подавить предупреждение, и это сделает это:
#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);
Обсуждение
Это может оскорбить вашу чувствительность, но она очень короткая и не имеет условий гонки (как это было бы, если бы вы использовали &i
). Нет смысла писать несколько десятков строк дополнительного кода, чтобы получить кучу нумерованных потоков.
Горы данных
Вот версия bad с расчетом данных:
#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;
}
Теперь, что происходит, когда я запускаю его с помощью дезинфицирующего средства для потока?
(Кроме того, проверьте, как он дважды печатает "5"...)
==================
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
Ответ 2
вы можете сделать что-то вроде этого:
#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);
}
выведет:
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
передача уникального указателя на каждый поток не будет участвовать в гонке, и вы можете получить/сохранить любую информацию в th struct
Ответ 3
изменения:
status=pthread_create(&th[i],NULL,print,(void *)i);
в
status=pthread_create(&th[i],NULL,print,(reinterpret_cast<void*>(i));
reinterpret_cast делает int размером указателя, и предупреждение останавливается. В основном это лучшая версия (void *) i.