4

I am currently working on a project that uses pthreads. The project so far starts a user specified number of threads and does some work on each thread then closes. Each thread is stored in a dynamically allocated array of memory. I do this using:

threads = malloc(number_of_threads * sizeof(pthread_t));

Then I create each thread in a for-loop:

pthread_create(&(threads[i]), NULL, client_pipe_run, (void *) &param[i]);

What I need to do next is store the return values of these threads. My understanding is that I need to pass pthread_join the address of a pointer I want to have the return value stored in. This is where I get a little confused. I'm fine with pointers up to this point then my brain kind of has a melt down haha. This is my idea on how to acheive this but I'm not confident that this is correct:

int *return_vals = malloc(sizeof(int) * number_of_threads);
for(i = 0; i< number_of_threads; i++)
{
pthread_join(&(threads[i]),(void *) &(return_vals[i]));
}

Then to get the return value I would do something similar to:

int val = *(return_val[0]);

Any help on the this would be greatly appreciated!

amura.cxg
  • 2,348
  • 3
  • 21
  • 44
  • have you checkout this post: http://stackoverflow.com/questions/2251452/how-to-return-a-value-from-thread-in-c – zzk Mar 04 '13 at 19:03

1 Answers1

7

Note that you are allocating memory for your threads like this:

threads = malloc(number_of_thread * sizeof(pthread_t));

but for return values you do:

int *return_vals = malloc(sizeof(int *));

i.e. number of threads should be taken in count here too:

int *return_vals = malloc(number_of_thread * sizeof(int));

Then you can either cast the return value to void*:

void *foo(void *arg) {
    int i = 7;
    return (void*)i;
}

int main(void) {
    int i = 0;
    int thread_count = 3;
    pthread_t* threads = malloc(thread_count * sizeof(pthread_t));
    int *return_vals = malloc(thread_count * sizeof(int));

    // create threads:
    for(i = 0; i < thread_count; ++i)
        pthread_create(&threads[i], NULL, &foo, NULL);

    // wait untill they finish their work:
    for(i = 0; i < thread_count; ++i)
        pthread_join(threads[i], (void**) &return_vals[i]);

    // print results:
    for(i = 0; i < thread_count; ++i)
        printf("Thread %d returned: %d\n", i, return_vals[i]);

    // clean up:
    free(return_vals);
    free(threads);

    return 0;
}

or you can make sure that your code doesn't make any presumptions about size of the type you're returning being less or equal to sizeof(void*) and allocate the memory for the return value dynamically within the thread:

void *foo(void *arg) {
    int* ret = malloc(sizeof(int));
    *ret = 7;
    return ret;
}

int main(void) {
    int i = 0;
    int thread_count = 3;
    pthread_t* threads = malloc(thread_count * sizeof(pthread_t));

    // array of pointers to return values of type int:
    int **return_vals = calloc(thread_count, sizeof(int*));

    // create threads:
    for(i = 0; i < thread_count; ++i)
        pthread_create(&threads[i], NULL, &foo, NULL);

    // wait untill they finish their work:
    for(i = 0; i < thread_count; ++i)
        pthread_join(threads[i], (void**) &return_vals[i]);

    // print results:
    for(i = 0; i < thread_count; ++i)
        printf("Thread %d returned: %d\n", i, *return_vals[i]);

    // clean up:
    for(i = 0; i < thread_count; ++i)
        free(return_vals[i]);
    free(return_vals);
    free(threads);

    return 0;
}

But in case you chose the latter one, be careful about possible memory leaks you might end up with.

LihO
  • 41,190
  • 11
  • 99
  • 167
  • Oops can't believe I left that out >.< Thank you for the answer! I really appreciate it :) – amura.cxg Mar 04 '13 at 19:31
  • 1
    @amura.cxg: Also note that you are creating an array of `int`s: so you should pass to `malloc` `sizeof(int) * number_of_threads`, not `sizeof(int*) * number_of_threads` – LihO Mar 04 '13 at 19:38
  • I tried the first implementation you suggested and when I try using `return_vals[i]` it gives me some large int (eg 134602832) when it should be 0 or -1. I do a memset on the array and set everything to 0 so the code does modify the value correctly but it doesn't put what I expect there. Is there something missing when trying to get the returned value out of the array? – amura.cxg Mar 04 '13 at 21:26
  • @amura.cxg: That's why I put there that `printf` too so that it's clear how those values should be used. Both of those examples work fine for me, have a look at it again and try to find analogy with your code. In case you're stuck with it, then post it as a new question, maybe there's another error. – LihO Mar 04 '13 at 22:00
  • @LihO why in the first example inside `foo` you're casting an `int` to `void *`? are we supposed to return like this: `return (void *) &i`? Because `void *` is a pointer as far as I understand and `i` is not. – Yos May 05 '18 at 10:41
  • @Yos That's the ugly "hotfix" cast to comply with `pthread_join`'s "generic" `void**` argument, a pointer to any kind of data. And you're right, it's not the best thing to do. That's why I wrote the second example back then. – LihO May 07 '18 at 02:04