Julien CRAMBES
Julien CRAMBES

Reputation: 51

Only first value returned from thread is wrong (C)

so I was doing C programming homework and I came across a weird behaviour of the threads : I gave a value to a thread and it gives it back into a pthread_exit() function, then I add all returned values in the main function. The problem is that only the first value is completely wrong which means that my transtyping is right but there's a memory problem I haven't managed to solve even with help.

Here's the code :

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void * fonction_thread(void * arg);

long s = 0; //int to sum on

int main (int argc, char* argv[])
{
    int N,i ; //N is the number of threads created
    void* ret ;  //returned value

    N= atoi(argv[1]);
    s=0;
    
    for(i=1; i<N+1; i++){

        //creation of the threads
        pthread_t thr;
        if (pthread_create(&thr, NULL, fonction_thread, &i) != 0) {
            fprintf(stderr, "Erreur dans pthread_create\n");
            exit(EXIT_FAILURE);
        }

        //recovering the value
        pthread_join(thr, &ret);
        printf("retour : %d\n\n", *((int*)ret)); //transtyping void* to int* before derefencement
        s+= *((int*)ret);   
    }
    printf("%ld\n", s);
}

//thread handler
void * fonction_thread(void * arg)
{
    int n;
    n = *((int *)arg); //recovering the value given by the main
    printf("thread numéro %d créé\n", n);
    pthread_exit((void*) &n); //casting then returning value
}

and here is the console view : console screeshot

Upvotes: 0

Views: 110

Answers (1)

Some programmer dude
Some programmer dude

Reputation: 409166

One major problem is that you return a pointer to the local variable n.

As soon as fonction_thread exits, the life-time of all local variables ends, and any pointer to them becomes invalid.

For something like this it's considered okay (barely) to cast values to pointers and back again, which means you could do something like this to return the value:

return (void *) (intptr_t) n;  // Or use pthread_exit((void *) (intptr_t) n)

Then when you receive the "pointer" you do the opposite cast:

int n = (int) (intptr_t) ret;

Note that you need to pass the value of i to the thread the same way. Not because of life-time issues, but because all threads will have the exact same pointer, and there will be a data-race to get the value which means multiple threads could seem to get the same value.

So when you create the thread pass the value:

pthread_create(&thr, NULL, fonction_thread, (void *) (intptr_t) i)

And in the function do the opposite cast to get the value:

int n = (int) (intptr_t) arg;

Upvotes: 3

Related Questions