devnull
devnull

Reputation: 463

Correct use of POSIX' pthread_exit and pthread_join

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

Answers (2)

Casey
Casey

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

Sandeep
Sandeep

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

Related Questions