How to return a value from pthread threads in C?

CPthreads

C Problem Overview


I'am new to C and would like to play with threads a bit. I would like to return some value from a thread using pthread_exit()

My code is as follows:

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

void *myThread()
{
   int ret = 42;
   pthread_exit(&ret);
}

int main()
{
   pthread_t tid;
   void *status;
 
   pthread_create(&tid, NULL, myThread, NULL);
   pthread_join(tid, &status);

   printf("%d\n",*(int*)status);   
 
   return 0;
}

I would expect the program output "42\n" but it outputs a random number. How can I print the returned value?

It seems to be a problem that I am returning a pointer to a local variable. What is the best practice of returning/storing variables of multiple threads? A global hash table?

C Solutions


Solution 1 - C

Here is a correct solution. In this case tdata is allocated in the main thread, and there is a space for the thread to place its result.

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

typedef struct thread_data {
   int a;
   int b;
   int result;

} thread_data;

void *myThread(void *arg)
{
   thread_data *tdata=(thread_data *)arg;

   int a=tdata->a;
   int b=tdata->b;
   int result=a+b;

   tdata->result=result;
   pthread_exit(NULL);
}

int main()
{
   pthread_t tid;
   thread_data tdata;

   tdata.a=10;
   tdata.b=32;

   pthread_create(&tid, NULL, myThread, (void *)&tdata);
   pthread_join(tid, NULL);

   printf("%d + %d = %d\n", tdata.a, tdata.b, tdata.result);   

   return 0;
}

Solution 2 - C

You are returning the address of a local variable, which no longer exists when the thread function exits. In any case, why call pthread_exit? why not simply return a value from the thread function?

void *myThread()
{
   return (void *) 42;
}

and then in main:

printf("%d\n", (int)status);   

If you need to return a complicated value such a structure, it's probably easiest to allocate it dynamically via malloc() and return a pointer. Of course, the code that initiated the thread will then be responsible for freeing the memory.

Solution 3 - C

You've returned a pointer to a local variable. That's bad even if threads aren't involved.

The usual way to do this, when the thread that starts is the same thread that joins, would be to pass a pointer to an int, in a location managed by the caller, as the 4th parameter of pthread_create. This then becomes the (only) parameter to the thread's entry-point. You can (if you like) use the thread exit value to indicate success:

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

int something_worked(void) {
    /* thread operation might fail, so here's a silly example */
    void *p = malloc(10);
    free(p);
    return p ? 1 : 0;
}

void *myThread(void *result)
{
   if (something_worked()) {
       *((int*)result) = 42;
       pthread_exit(result);
   } else {
       pthread_exit(0);
   }
}

int main()
{
   pthread_t tid;
   void *status = 0;
   int result;

   pthread_create(&tid, NULL, myThread, &result);
   pthread_join(tid, &status);

   if (status != 0) {
       printf("%d\n",result);
   } else {
       printf("thread failed\n");
   }

   return 0;
}

If you absolutely have to use the thread exit value for a structure, then you'll have to dynamically allocate it (and make sure that whoever joins the thread frees it). That's not ideal, though.

Solution 4 - C

I think you have to store the number on heap. The int ret variable was on stack and was destructed at the end of execution of function myThread.

void *myThread()
{
   int *ret = malloc(sizeof(int));
   if (ret == NULL) {
       // ...
   }
   *ret = 42;
   pthread_exit(ret);
}

Don't forget to free it when you don't need it

Another solution is to return the number as value of the pointer, like Neil Butterworth suggests.

Solution 5 - C

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

void* myprint(void *x)
{
    int k = *((int *)x);
    printf("\n Thread created.. value of k [%d]\n", k);
    //k =11;
    pthread_exit((void *)k);
}

int main()
{
    pthread_t th1;
    int x =5;
    int *y;
    pthread_create(&th1, NULL, myprint, (void*)&x);
    pthread_join(th1, (void*)&y);
    printf("\n Exit value is [%d]\n", y);
}  

Solution 6 - C

You are returning a reference to ret which is a variable on the stack.

Solution 7 - C

Question : What is the best practice of returning/storing variables of multiple threads? A global hash table?

This totally depends on what you want to return and how you would use it? If you want to return only status of the thread (say whether the thread completed what it intended to do) then just use pthread_exit or use a return statement to return the value from the thread function.

But, if you want some more information which will be used for further processing then you can use global data structure. But, in that case you need to handle concurrency issues by using appropriate synchronization primitives. Or you can allocate some dynamic memory (preferrably for the structure in which you want to store the data) and send it via pthread_exit and once the thread joins, you update it in another global structure. In this way only the one main thread will update the global structure and concurrency issues are resolved. But, you need to make sure to free all the memory allocated by different threads.

Solution 8 - C

if you're uncomfortable with returning addresses and have just a single variable eg. an integer value to return, you can even typecast it into (void *) before passing it, and then when you collect it in the main, again typecast it into (int). You have the value without throwing up ugly warnings.

Solution 9 - C

#include <pthread.h>
#include <stdio.h>
#include <stdint.h>

void *myThread(void *args)
{
	return (void *)(intptr_t)42;
}

int main(void)
{
	pthread_t tid;
	void *status;
	int ret;

	pthread_create(&tid, NULL, myThread, NULL);
	ret = pthread_join(tid, &status);

	if (ret) {
		fprintf(stderr, "pthread_join() failed\n");
		return -1;
	}

	/* pthread_join() copies the exit status (namely 42) of the target thread
	 * into the location pointed to by retval (namely &status), &status points
	 * to void *, so we need to cast void * to int.
	 */
	printf("%ld\n", (intptr_t)status);

	return 0;
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPetr PellerView Question on Stackoverflow
Solution 1 - CsalsamanView Answer on Stackoverflow
Solution 2 - CanonView Answer on Stackoverflow
Solution 3 - CSteve JessopView Answer on Stackoverflow
Solution 4 - CMessaView Answer on Stackoverflow
Solution 5 - CAbhishekView Answer on Stackoverflow
Solution 6 - CMaurits RijkView Answer on Stackoverflow
Solution 7 - CJayView Answer on Stackoverflow
Solution 8 - CAdityaView Answer on Stackoverflow
Solution 9 - ClifangView Answer on Stackoverflow