1

I wrote this small program for understanding pthread_create and pthread_join but I dont understand why the value of the variable data gets altered after thread_join. Its printed as 0 after the call to pthread functions.

#include <pthread.h>
#include <stdio.h>
void* compute_prime (void* arg)
{
        int n = *((int*) arg);
        printf("Argument passed is %d\n",n);
        return (void *)n;
}
int main ()
{
        pthread_t thread;
        int data = 5000;
        int value=0;

        pthread_create (&thread, NULL, &compute_prime, &data);
        pthread_join (thread, (void*) &value);
        printf("The number is %d and return value is %d.\n", data, value);
        return 0;
}

And the output is

Argument passed is 5000
The number is 0 and return value is 5000.
Karthick
  • 1,010
  • 1
  • 8
  • 24
  • `value` in `pthread_join` is set to the return value of the thread. Herein, this means that would be the value of `n` returned by the thread function – Craig Estey Jul 13 '17 at 15:45
  • @CraigEstey the question is why `data` changes. And I don't see anything in this code changing it, even with the ill cast in `return (void *)n;`. There might be code missing. –  Jul 13 '17 at 15:46
  • `return (void *)n;` is returning a pointer to a local variable, isn't it? – duong_dajgja Jul 13 '17 at 15:51
  • @duong_dajgja no, it just casts the `int` to a `void *`. But this isn't a safe thing to do in general. (and it's indeed the source of the problem) –  Jul 13 '17 at 15:55

1 Answers1

5

This is because pthread_join has the prototype void **. It expects a pointer to an object of type void *; it modifies this void * object. Now it so happens that you're running on a 64-bit arch, where data and value are both 32 bits, and laid out in memory sequentially. Modifying a void * object that is laid out in memory starting from the address of the int object value clobbers the int object data too, as these are both 32 bits - thus you will see that the data was overwritten. However, this is undefined behaviour so anything might happen.


Don't use casts as they will only serve to hide problems. Casting to a void * is especially dangerous as a void * can be converted to any other type implicitly, even to void **, even though usually it too would be incorrect. If you remove the cast, you most probably will get a warning or an error like

thrtest.c: In function ‘main’:
thrtest.c:16:31: error: passing argument 2 of ‘pthread_join’ from 
                incompatible pointer type [-Werror=incompatible-pointer-types]
         pthread_join (thread, &value);

if compiling with warnings enabled.


If however you really want to do this, you must do it like this:

void *value;
pthread_join(thread, &value);
intptr_t value_as_int = (intptr_t)value;

Though it is not really portable either, as the conversion is implementation-defined.

The most portable way to return an integer is to return a pointer to a mallocated object:

int *return_value = malloc(sizeof (int));
*return_value = 42;
return return_value;

...

void *value;
pthread_join(thread, &value);
int actual = *(int *)value;
free(value);
  • if you just want to return a number from a thread function, converting it to `intptr_t` comes to mind, though... –  Jul 13 '17 at 15:58
  • yeah, then can confirm this by defining data as `unsigned long long int`? – duong_dajgja Jul 13 '17 at 16:02
  • The only portability issue with `intptr_t` would be the range of values representable in `void *`.... As this is a POSIX function, it would be an interesting question whether POSIX is giving guarantees that make this bullet-proof (it's somewhat common to return a single number that way, at least) –  Jul 13 '17 at 16:09
  • You certainly can take an arbitrary pointer, convert it to `intptr_t` on POSIX and then back again, but I would be a bit more hesitant about converting an arbitrary integer to a pointer... – Antti Haapala -- Слава Україні Jul 13 '17 at 16:12
  • @AnttiHaapala yes, it must be representable in `void *` and that's not guaranteed by C. But maybe it is by POSIX, I don't know... –  Jul 13 '17 at 16:14