Reputation: 3086
Consider the following code:
void* run(void* arg) {
int* array=(int*)arg;
printf("In run!\n");
int i;
for (i=0; i<10; i++) {
printf("%d ",array[i]);
}
printf("\n");
return (void*)15;
}
int main() {
pthread_t my_thread;
int array[10]={0};
void* ret;
int i;
for (i=0; i<10; i++) {
array[i]=i+1;
}
if (pthread_create(&my_thread, NULL, run, (void*)array)!=0) {
perror("thread creation failed");
return 1;
}
pthread_join(my_thread, &ret);
printf("thread finished and returned %d\n", *(int*)ret); // segfault. why??
return 0;
}
I'm trying to obtain the value 15, returned by the thread that was created, but for some reason, that last printf throws segmentation fault.
What is the reason for the segmentation fault, and what is the right way to obtain the returned value 15?
I also tried this:
printf("thread finished and returned %d\n", *(*(int*)ret));
Which resulted in an error:
error: invalid type argument of unary ‘*’ (have ‘int’)
and this:
printf("thread finished and returned %d\n", *(int*)(*ret));
which also resulted in an error (and a warning):
warning: dereferencing ‘void *’ pointer [enabled by default]
error: invalid use of void expression
What is the right way to do it, and most importantly, what is the reason for that segfault?
Upvotes: 1
Views: 1868
Reputation: 726539
The reason for the failure is that your thread returns an integer in place of a void*
, and the code in main
tries to dereference it.
It is illegal to do both these things at once, but you can do each one of them separately:
int
in a pointer, you could cast it to uintptr_t
before casting to void*
, and do the sequence in reverse to get back an int
, ormain
, you need to put your int
in memory, and pass back a pointer to that memory so that it could be dereferenced in main
.I would use the first approach, like this:
// Inside run():
return (void*)((uintptr_t)15);
// Inside main():
printf("thread finished and returned %d\n", (int)((uintptr_t)ret));
Remember to include <stdint.h>
in order to use the uintptr_t
type.
Using the second approach is a bit trickier:
// Inside run():
int *ret = malloc(sizeof(int)); // You need to use dynamic allocation here
*ret = 15;
return ret;
// Inside main():
int *run_ret = ret;
printf("thread finished and returned %d\n", *run_ret);
free(run_ret); // You need to free malloc-ed memory to avoid a leak
You could potentially simplify it by allocating the buffer for the result in the caller, but either way that is going to be harder than using the uintptr_t
approach.
Upvotes: 4