1

I used pthread_join function met a problem at yesterday,it's appear complie error, I have search it long time on net, but have no solve it.

pthread_join.c:

#include  <stdio.h>

#include  <pthread.h>

void* say_hello(void* args)
{

    printf("hello from thread\n");
    pthread_exit((void*)1);
}

int main()
{

    pthread_t tid;
    int iRet=pthread_create(&tid,NULL,say_hello,NULL);
    if(iRet)
    {
            printf("pthread create error:iRet=%n\n",iRet);
            return iRet;
    }

    void *retval;
    iRet=pthread_join(tid,&retval);
    if(iRet)
    {
            printf("pthread_join error:iRet=%d\n",iRet);
            return iRet;
    }


       printf("retval=%ld\n",(long)**(&retval));
      // printf("retval=%ld\n",(long)retval); 
       return 0;
}

error:

 $ error:invalid use of void expression

I try to use (&retval) to get return value of pthread_join. I feel the retval belong to void** , then I use (retval) should can get value ,but failed .I'm can't use void to get the values of ** pointer,I guess the retval was been the value by pthread_join,but if use **retval to get it, can't successful.

I used gcc compiled it , it will display:

  $ error:invalid use of void expression       
alk
  • 69,737
  • 10
  • 105
  • 255
Marcos
  • 111
  • 1
  • 2
  • 5

2 Answers2

3

Why can't use ** to get return value of pthread_join

void *retval;
...
printf("retval=%ld\n",(long)**(&retval));

retval is a void*, &retval is a void**, so **(&retval) is void. You then are trying to cast a void to a long, which is not possible. This is why you get from gcc : error:invalid use of void expression.

A posix thread start routine must return a value of type void*. In say_hello(), you return an int (1) properly casted to void*, as required.

pthread_join(pthread_t thread, void **value_ptr) requires, as the 2nd parameter, an adress to a void* to store the return value of the joined thread. By calling pthread_join(tid,&retval), you properly provide to pthread_join() the address of retval which is void*. Doing so, the thread return value, (void*)1, is stored into retval.

Now, if you want to print the return value retval, casted to a long, the correct syntax is the one you commented out :

printf("retval=%ld\n",(long)retval);

You could also have written this as follows :

printf("retval=%ld\n",(long)*(&retval));

which is equivalent though does not make many sense...

shrike
  • 4,449
  • 2
  • 22
  • 38
  • why it can use void* stored return value, void* is a ponter , it's a address ,the address can store value ? I don't understand it. – Marcos Oct 04 '16 at 01:44
  • 1
    @Marcos: `void*` usually represent a memory address but not necessarily; in function `say_hello()`, you casted an `int` (1) into a `void*`, meaning you used a `void*` to store an `int` value, which thus does not represent a valid memory address. So yes, a pointer can store a value which is not an address. – shrike Oct 04 '16 at 11:05
  • @Marcos Yes, it's designed to use a pointer to store a return value. You can't dereference it by doing `*ptr`, you can only print the pointer's value. Why use a pointer? Superficially, with a pointer, you can return "limited integer value" or **a pointer to a structure**(One Stone And Two Birds). To understand this thoroughly, you might need to check the implementation of these functions, which is too hard for me. – Rick Apr 08 '19 at 03:07
0

Referring this comment: Why can't use ** to get return value of pthread_join another answer here.

This

  ...

  pthread_exit((void*) 1);
}

might lead to a trap condition and with this to undefined behaviour.

So the right way to return a value of 1 on the thread's termination would be:

  ...

  int * pi = malloc(sizeof *pi);
  /* Add error checking an handling for malloc() here. */
  *pi = 1;

  pthread_exit(pi); /* No need to cast in C. */
}

Inside the thread joining the other thread do:

  ...

  {
    void * pv;
    pthread_join(..., &pv); /* Add error checking and handling for pthread_join(). */ 

    printf("thread returned: %d\n", *((int*) pv));

    free(pv); /* Free what the other thread allocated (see above). */
  }     

  ...
alk
  • 69,737
  • 10
  • 105
  • 255