Accessing the return value using pthread_exit()

2.5k Views Asked by At

I have done the following code.

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

struct foo
{
   int a;
   int b;
};

void* thread_func1(void *arg)
{
   struct foo *temp = (struct foo*)malloc(sizeof(struct foo));

   temp->a = 10;
   temp->b = 20;

   pthread_exit(temp);
}

void* thread_func2(void *arg)
{
   pthread_exit((void*)100);
}

int main()
{
   pthread_t tid1, tid2;
   int err;
   struct foo *f;
   void *ret;

   err = pthread_create(&tid1, NULL, thread_func1, NULL);
   err = err | pthread_create(&tid2, NULL, thread_func2, NULL);

   if(err != 0)
   {
      perror("pthread_create()");
      exit(-1);
   }

   err = pthread_join(tid1, (void**)&f);
   if(err != 0 )
   {
      perror("pthread_join1");
      exit(-1);
   }

   printf("a = %d, b = %d\n", f->a, f->b); //Line1

   err = pthread_join(tid2, &ret);
   if(err != 0 )
   {
      perror("pthread_join2");
      exit(-1);
   }

   printf("ret = %d\n", *(int*)ret); //Line2

   return 0;

}

I get segmentation fault on Line2. What is wrong with Line2

If i modify Line2 to

printf("ret = %d\n", (int)ret);

there is no segmentation fault and it prints the correct value(ie, 100). I do not understand why the modification works. I believe i have the wrong concept regarding the usage of double pointers. I would like to get it corrected.

What is the reason for the Segmentation fault and why the modification works?

4

There are 4 best solutions below

0
On BEST ANSWER

You return one number from the thread. In the first thread, that number is a struct foo *. Therefore, if you say

pthread_join(tid1, &ret);

then ret will contain that pointer (which is not a double pointer).

Similarly in the second case, you are returning 100 even though you are looking at it as if it's a void *. Nevertheless, the value is still 100!

Therefore when you write

pthread_join(tid2, &ret);

ret will contain 100, which is not a pointer, but a mere integer. That is why you should also cast it to int.

The reason you got a segmentation fault is that you look at 100 as an int * and then try to dereference it.

1
On

That's because you are returning the actual integer, not a pointer, but you access it as a pointer.

0
On

Its because you're trying to dereferencce a pointer whose address is 100.

Instead of looking at the return value, why dont you pass in a pointer to what you want to assign in the thread_funcs? That is, use the "void *arg" arguments of thread_func1() and thread_func2()

Like this:

void* thread_func1(void *arg)
{
   struct foo **fooPtrPtr = (struct foo**) arg;
   *fooPtrPtr = (struct foo*)malloc(sizeof(struct foo));

   ...
}

void* thread_func2(void *arg)
{
   int *intPtr = arg;
   *intPtr = 100;
   ...
}

int main()
{
   pthread_t tid1, tid2;
   int err;
   struct foo *f;
   int ret;

   err = pthread_create(&tid1, NULL, thread_func1, &f);
   err = err | pthread_create(&tid2, NULL, thread_func2, &ret);
   ...
   printf("a = %d, b = %d\n", f->a, f->b); //Line1
   ...
   printf("ret = %d\n", ret); //Line2
   ...
}
0
On

pthread_exit((void*)100); causes integer 100 to become exit status of your thread. It just abuses type cast so that void* is its type. If you want to retrieve this value, you will have to use same type cast abuse in main thread as well:

int ret;
err = pthread_join(tid2, (void**) &ret);
// here you can work with ret as with any other integer

I also suggest you to use return instead of pthread_exit. Also note that memory dynamically allocated by using malloc should be freed by calling free. And type cast of return value of malloc is redundant here, it can be omitted.

This question could also help you: Close a thread when done with it