Reputation: 463
I'm trying to get the concepts of returning a value from a pthread, and catching that value, but I cannot understand what is going on, or how to make it work. I have this simple program that creates a single thread, this thread exits with int value 100, and then I try to catch that value with pthread_join:
#include <stdio.h>
#include <pthread.h>
void *doStuff(void *param) {
int a = 100;
pthread_exit(a);
}
void main() {
pthread_t thread;
int a;
pthread_create(&thread, NULL, doStuff, NULL);
pthread_join(thread, &a);
printf("%d\n", a);
}
It works, but throws off a few warnings:
./teste.c: In function ‘doStuff’:
./teste.c:7:2: warning: passing argument 1 of ‘pthread_exit’ makes pointer from integer without a cast [enabled by default]
In file included from ./teste.c:2:0:
/usr/include/pthread.h:241:13: note: expected ‘void *’ but argument is of type ‘int’
./teste.c: In function ‘main’:
./teste.c:17:2: warning: passing argument 2 of ‘pthread_join’ from incompatible pointer type [enabled by default]
In file included from ./teste.c:2:0:
/usr/include/pthread.h:249:12: note: expected ‘void **’ but argument is of type ‘int *’
I don't understand why I'm getting those warnings, and honestly I don't understand why this is working either, because I thought I had to return a void pointer on pthread_exit.
This is a simple example that I'm trying to get to work so that I'm able to finish another program that I'm trying to create, in which I will have an array of threads, each of them calculating a single float value, and I want to store each of those calculated values into an array of floats using pthread_exit and pthread_join, but I don't really know how to store the values from pthread_join into an array.
Upvotes: 1
Views: 7346
Reputation: 42554
pthread_exit
takes a void*
, not an int
. (Note that calling pthread_exit(x)
is the same as simply returning x
from your thread function.)
The simplest fix for your issue is to pass the thread function a pointer to int
in which to store the produced value:
void *doStuff(void *param) {
int a = 100;
*(int*)param = a;
return NULL;
}
int main(void) {
pthread_t thread;
int a;
pthread_create(&thread, NULL, doStuff, &a);
pthread_join(thread, NULL);
printf("%d\n", a);
}
EDIT: If you really need to use the return value of the thread function as to communicate the result, you have a couple of options.
(1) cast the return value in and out of void*
:
void *doStuff(void *param) {
int a = 100;
return (void*)a;
}
int main(void) {
pthread_t thread;
pthread_create(&thread, NULL, doStuff, NULL);
void* ptr;
pthread_join(thread, &ptr);
int a = (int)ptr;
printf("%d\n", a);
}
This feels a bit hackish, because it is. If you are certain that casting to-and-from void*
will preserve the value of an int
on every platform you will ever target, then by all means cast away.
(2) Return a pointer to dynamically allocated storage containing the return value:
void *doStuff(void *param) {
int a = 100;
int* ptr = malloc(sizeof(*ptr));
assert(ptr); /* I'm lazy, sue me. */
*ptr = a;
return ptr;
}
int main(void) {
pthread_t thread;
pthread_create(&thread, NULL, doStuff, NULL);
void* ptr;
pthread_join(thread, &ptr);
int a = *(int*)ptr;
free(ptr);
printf("%d\n", a);
}
(3) Make a structure to encapsulate all the in/out parameters of your thread (Heavyweight, but nicely explicit):
struct foo {
int input1;
int input2;
int result;
};
void *doStuff(void *param) {
foo* f = param;
f->result = f->input1 + f->input2;
return NULL;
}
int main(void) {
foo* ptr = malloc(sizeof(*ptr));
assert(ptr);
ptr->input1 = 5;
ptr->input2 = 3;
pthread_t thread;
pthread_create(&thread, NULL, doStuff, ptr);
pthread_join(thread, NULL);
printf("%d\n", ptr->result);
free(ptr);
}
Upvotes: 5
Reputation: 19452
Just adding one more way to avoid all warnings. I have actually got this solution by reading multiple SO answers.
void *thread_fn(void *arg) {
int a = 100;
return (void*)(intptr_t)a;
}
int main(void) {
pthread_t thread;
void* ptr;
int a;
pthread_create(&thread, NULL, thread_fn, &a);
pthread_join(thread, &ptr);
a = (intptr_t)ptr;
printf("%d\n", a);
}
In the above code snippet, return (void*)(intptr_t)a;
here we are first type casting integer to get an integer type that's the same size as a pointer(intptr_t). And then we can now typecast it to void pointer. Same is the case with a = (intptr_t)ptr;
Upvotes: 0