I was trying to print a thread's return value and discovered that I'm still quite confused by the notion of double void-pointers.
My understanding was that a void* is a pointer to any datatype that can be dereferenced with an appropriate cast, but otherwise the "levels" of referencing are preserved like with regular typed pointers (i.e. you can't expect to get the same value that you put into **(int **)depth2 by dereferencing it only once like *depth2. ).
In the code (below) that I have scraped together for my thread-return-print, however, it seems that I'm not dereferencing a void pointer at all when I'm just casting it to (int). Is this a case of an address being used as value? If so, is this the normal way of returning from threads? Otherwise, what am I missing??
(I am aware that the safer way to manipulate data inside the thread might be caller-level storage, but I'm quite interested in this case and what it is that I don't understand about the void pointer.)
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void *myThread(void *arg)
{
return (void *)42;
}
int main()
{
pthread_t tid;
void *res; // res is itself a void *
pthread_create(&tid, NULL, myThread, NULL);
pthread_join(tid, &res); // i pass its address, so void** now
printf(" %d \n", (int)res); // how come am i able to just use it as plain int?
return 0;
}
First of all, the purpose of pthread_join() is to update the void *
given through its second argument in order to obtain the result of the
thread function (a void *).
When you need to update an int as in scanf("%d", &my_var); the argument
is the address of the int to be updated: an int *.
With the same reasoning, you update a void * by providing a void **.
In the specific situation of your example, we don't use the returned
void * in a normal way: this is a trick!
Since a pointer can be thought about as a big integer counting the bytes in
a very long row, the trick is to assume that this pointer can simply store
an integer value which does no refer to any memory location.
In your example, returning (void *)42, is equivalent to saying
"you will find something interesting at address 42".
But nothing has ever been placed at this address!
Is this a problem? No, as long as nobody tries to dereference this
pointer in order to retrieve something at address 42.
Once pthread_join() has been executed, the variable res has
been updated and contains the returned void *: 42 in this case.
We perform here the reverse-trick by assuming that the information memorised
in this pointer does not refer to a memory location but is a simple integer.
It works but this is very ugly!
The main advantage is that you avoid the expensive cost of malloc()/free()
void *myThread(void *arg)
{
int *result=malloc(sizeof(int));
*result=42;
return result;
}
...
int *res;
pthread_join(tid, &res);
int result=*res; // obtain 42
free(res);
A better solution to avoid this cost would be to use the parameter
of the thread function.
void *myThread(void *arg)
{
int *result=arg;
*result=42;
return NULL;
}
...
int expected_result;
pthread_create(&tid, NULL, myThread, &expected_result);
pthread_join(tid, NULL);
// here expected_result has the value 42
Related
I am having a hard time understanding why pthread_join's retval argument is a void**. I have read the manpage and tried to wrap my head around it but I still cannot fully understand it. I couldn't convince myself that retval cannot be a void*. Could someone please enlighten me?
Thank you very much in advance!
It's because you are supposed to supply the address of a void* to pthread_join.
pthread_join will then write the address supplied by pthread_exit(void*) into the variable (who's address you supplied).
Example scenario:
typedef struct {
// members
} input_data;
typedef struct {
// members
} output_data;
Starting thread side:
input_data id;
pthread_create(..., start_routine, &id);
void* start_routine(void *ptr) {
input_data *id = ptr;
output_data *od = malloc(sizeof *od);
// use the input data `id`, populate the output data `od`.
pthread_exit(od);
}
Joining side:
output_data *od;
pthread_join((void**) &od);
// use `od`
free(od);
Simple enough. The return value of thread func supplied to pthread_create is void*; pthread_join is supposed to return this value to caller.
It can not return this as a function return type (because it is already returning int to indicate the overall status of the call). The only other way as through out parameter.
And the way C does out paramters is by using a pointer to the actual type of the parameter - i.e. if you want to do int as an out parameter, the type of the argument would be int*. If your out parameter is void* (because this is what you are returning from pthread func!), the type of the argument becomes void**.
As an exercise, you can try to write a similar code yourself - first, create a function which returns void* (say, void* foo()), and than try to write another function which would call foo() and communicate result back to the caller.
The exiting thread is going to provide a pointer to some data. The pthread routines do not know what type that data has, so they receive the pointer as a void *.
The caller of pthread_join is going to receive that void *. Since the function return value is used for something else, the void * has to be received through a parameter. So the caller has to pass a pointer to where pthread_join will put the void *. That pointer is a pointer to a void *, which is a void **.
From the manpage:
If retval is not NULL, then pthread_join() copies the exit status of the target thread (i.e., the value that the target thread supplied to pthread_exit(3)) into the location pointed to by retval.
Let's look at the signature of pthread_exit.
noreturn void pthread_exit(void *retval);
So that means if we wanted to return an int from our thread it would look something like this:
void* foo() {
// ...
int value = 255;
pthread_exit(&value);
}
This works because the compiler doesn't care that it's an int* or a void*, either way it's a pointer of the same size.
Now we want to actually extract the return value of the thread using pthread_join.
void bar() {
pthread_t thread_id;
int *returnValue;
// create thread etc...
// the original type of returnValue was an `int*` so when we pass it in
// with "&" it's now become `int**`
pthread_join(thread_id, &returnValue);
printf("%d\n", *returnValue); // should print 255
}
In plain English pthread_join takes a pointer and sets it address to point at the retval from your thread. It's a void** because we need the address of the pointer to be able to set the underlying pointer to what we want.
I think the print result should be 500, but the result was weird - it said 32728, which is meaningless.
#include<stdio.h>
#include<pthread.h>
void* testFunction(void*);
int main(void)
{
void* result;
pthread_t tid;
pthread_create(&tid, NULL, testFunction, NULL);
pthread_join(tid, &result);
printf("%d\n", *((int*)result));
}
void* testFunction(void* args)
{
int time;
time = 500;
pthread_exit((void*)&time);
}
In this code, this is the flow of what I thought
(void*)result has time's address.
(int*)result has time's address. Because of (int*), the program should know result variable is referring to int-type variable.
*((int*)result) means the value of what result variable refers to, so it would be time's value, which is 500.
Can you let me know what I thought wrong?
The problem is that time no longer exists by the time you come to check it. One way around that is to play with the casting. Instead of
pthread_exit((void*)&time);
use
pthread_exit((void*)time);
Then, when you are extracting the result, use
*((int) result)
Another minimal fix is to make time a static. That way, it is not stored in the stack and always exists.
What's wrong is that time is going out of scope when the thread function exits, meaning that dereferencing its address is undefined behaviour. And you are dereferencing after that, since it happens after the pthread_join() call.
There's a chance that something else will be using that memory (probably on the stack but no mandated, since a stack isn't itself mandated), which would explain the strange value.
But, regardless of what's actually happening, it's not something you're allowed to do in C. Or, more correctly, you can do it, just don't expect sane results.
As others already pointed out, the problem is that the pointer received by pthread_join() points nowhere the moment the function returned. As the memory allocate for int time has already been deallocated, as the function has already ended.
There are two possibilities to have pthread_join() return a pointer to valid memory:
Have the thread function allocate it dynamically.
#include <stdlib.h> /* For malloc() and free(). */
#include <stdio.h>
#include <pthread.h>
void* testFunction(void* pv_unused)
{
int * ptime = malloc(sizeof *ptime);
/* Add error checking/handling here! */
*ptime = 500;
pthread_exit(ptime);
}
int main(void)
{
...
pthread_join(tid, &result);
printf("%d\n", *((int*)result));
free(result); /* Free the memory that has been allocated by the thread-function. */
}
Pass a pointer to valid memory to the thread-function.
#include <stdio.h>
#include <pthread.h>
void* testFunction(void* pv_time)
{
int * ptime = pv_time;
*ptime = 500;
pthread_exit(ptime);
}
int main(void)
{
pthread_t tid;
int time;
pthread_create(&tid, NULL, testFunction, &time);
{
void * pv;
pthread_join(tid, &pv);
if (pv != &time)
{
/* Something went wrong! */
}
}
printf("%d\n", time);
}
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
struct Array
{
//
};
void* evensum(void* param)
{
//calculated the sum of even elements and returned it
}
void* oddsum(void* param)
{
//did the same thing but for odd elements
}
int main()
{
struct Array* obj=malloc(sizeof(struct Array));
//did all the inputs
int evensum,oddsum;
pthread_t thread1,thread2;
pthread_create(&thread1,0,&evensum,(void*)obj);
int evensum,oddsum;
pthread_join(&thread,(void**)evensum);
pthread_create(&thread2,0,&oddsum,(void*)obj);
pthread_join(&thread2,(void**)oddsum);
//try to print it using %i but I get or %d
// I get the sum as zero
}
So I created two separate threads and these threads were meant to work asynchronously. I followed the advice mentioned here but the join still doesn't work as once the thread1 finishes execution, the other thread is never created despite me following the correct syntax. Any idea how to fix this?
Also, the value printed is zero, despite showing the correct value if I print it in the function.
Here is what I wrote in the return statement of each function:
return (void*)sum;//variable that stores sum
Also, I want to add that I don't want to use semaphores or any other synchronization tool to do this.
The second parameter to pthread_join is a void **, i.e. it expects a pointer to a void * which it dereferences to store the value in. Because you're not passing the address of a variable, this function will attempted to use whatever value you passed in as an address (which would likely be invalid) and dereference it. This invokes undefined behavior.
Also, the first parameter is of type pthread_t but you're passing a pointer to a pthread_t.
You're also declaring local variables with the same names as the functions you're calling. As a result, when you call pthread_create(&thread2,0,&oddsum,(void*)obj); you're actually passing the local int variable called oddsum and not the function called oddsum. That's why it hangs.
Changing the name of the variables to hold the results, changing the pthread_join calls to pass the addresses of these variables and passing the thread IDs directly should work:
int evenresult;
pthread_join(thread,(void**)&evenresult);
...
int oddresult;
pthread_join(thread2,(void**)&oddresult);
The proper way to do retrieve the result however would be to pass the addresses of actual void * variables and converting them:
int evenresult, oddresult;
void *result;
pthread_join(thread, &result);
evensum = (intptr_t)result;
...
pthread_join(thread2, &result);
oddsum = (intptr_t)result;
Create all the thread and then join them like below:-
pthread_create(&thread1,0,&evensum,(void*)obj);
pthread_create(&thread2,0,&oddsum,(void*)obj);
pthread_join(&thread1,(void**)evensum);
pthread_join(&thread2,(void**)oddsum);
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.
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);
pthread_create(&Thread,NULL,ChildThread,(void *)100);
1) Can we pass the 4th argument of pthread_create as shown above? shouldn't it be a pointer variable?
Just an example (not meant to be correct way of doing it; but to serve as example code for anyone who want to play with it):
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#include <pthread.h>
void *print_number(void *number) {
printf("Thread received parameter with value: %d\n", number);
return (void *)number;
}
int main(int argc, char *argv[]) {
pthread_t thread;
void *ret;
int pt_stat;
pt_stat = pthread_create(&thread, NULL, print_number, (void *)100);
if (pt_stat) {
printf("Error creating thread\n");
exit(0);
}
pthread_join(thread, &ret);
printf("Return value: %d\n", ret);
pthread_exit(NULL);
return 0;
}
This will lead to undefined behavior if the pointer value is greater then what an int can hold. See this quote from C99:
Any pointer type may be converted to an integer type. Except as previously specified, the result is implementation-defined. If the result cannot be represented in the integer type, the behavior is undefined. The result need not be in the range of values of any integer type.
What (void *)100 means is take the integer value 100 and treat it as a pointer to some unspecified type of memory (i.e., (void *)). In that case, that means push the integer value 100 on the stack as an argument to pthread_create. Presumably, ChildThread casts the void * passed to it back to an int, then uses it as a number.
Fundamentally pointers are really just memory addresses. A memory address is just a number that describes a location in memory, so casting an int to a pointer of any type is legal. There are a few cases where casting an int to a pointer is absolutely the right thing to do and required, however, they tend to be rare. For example, if you are writing code for an embedded controller, and want write a driver for a memory mapped I/O device, then you might cast the device's base address as a pointer to an int or struct and then do normal C accesses through the pointer to access the device. Another example where casting ints to pointers, would be to implement the low-level virtual memory management routines to parcel out physical memory for an operating system.
The code you present is not uncommon and will work, assuming that the size of a pointer is at least big enough to hold the integer you are trying to pass. Most systems that implement pthread_create would probably have a 32-bit or 64-bit pointer, so your example is pretty likely to work. IMHO, it is a bit of an abuse, because 100 probably does not refer to a memory location in this case, and C does not guarantee that a void * is big enough to hold an int.
Taken from an excellent artice on POSIX Thread Progreamming . Must read for any newbie .
Example Code - Pthread Creation and Termination
#include <pthread.h>
#include <stdio.h>
#define NUM_THREADS 5
void *PrintHello(void *threadid)
{
long tid;
tid = (long)threadid;
printf("Hello World! It's me, thread #%ld!\n", tid);
pthread_exit(NULL);
}
int main (int argc, char *argv[])
{
pthread_t threads[NUM_THREADS];
int rc;
long t;
for(t=0; t<NUM_THREADS; t++){
printf("In main: creating thread %ld\n", t);
rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t);
if (rc){
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
/* Last thing that main() should do */
pthread_exit(NULL);
}
Explanation :
You can pass the 100 as the 4th argument to the pthread_create() . In the function PrintHello you can typecast the void* back into the correct type .