Is it legitimate to pass an argument as void*? - c

I have just started learning pthreads API and I am following the tutorial here
However, in an example program of pthread_create, the sample program creates a long variable and passes its value, typecasted as void*. In the thread entry function, it dereferences it just like a long.
Is this legit?
I understand if I pass the address of variable t, every thread would be acting on the same variable and not on a copy of it. Can we do this because it's a void* and the compiler has no idea about what type we are sending?
#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);
}
}
pthread_exit(NULL);
}

This works as long as sizeof(long) <= sizeof(void*), and that every value of long can be represented as a void*.
Better would be to pass the address of the variable. You can cast from a T* to void*, and back again safely and without assumption.

It's as legitimate as any kind of typecasting. The point is that nothing can be done with the value the argument points to, until it is typecast, hence tid = (long)threadid.
Check the older Q&A When to use a void pointer?.

Related

How to pass an argument to a pthread thread function in C?

Is it possible to pass an argument to the thread function in pthreads?
Say I create a thread:
int main() {
pthread_t t1;
pthread_create(&t1, NULL, callback, 10);
pthread_join(t1, NULL);
return 0;
}
And in callback I would like to just print out the 10. My problem now is that as per the C pthread API, the pthread_create() function signature is:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
Can I pass a pointer to an integer to the thread function and how?
You could use a variable, like:
int val = 10;
pthread_create(&t1, NULL, callback, &val);
pthread_join(t1, NULL);
...
And in the callback:
void* callback(void *arg)
{
int i = *(int *)arg;
....
return NULL;
}
Note that this works because the lifetime of val is valid until the thread (callback) completes its execution as you wait with pthread_join(). Otherwise, you may want to allocate memory dynamically (e.g. malloc) and pass that object to the thread function.
For a single value of integer type not wider than intptr_t, it possible and fairly common to cast it to a pointer in the pthread_create call and cast it back in the thread function:
int main() {
pthread_t t1;
pthread_create(&t1, NULL, callback, (void *) 10);
pthread_join(t1, NULL);
return 0;
}
void *t1(void *arg) {
int arg_as_int = (int) arg;
// ...
}
Such casting is definitely allowed, and again, is pretty conventional.
I have recently started seeing objections to this approach here on SO, however, on the basis that the C standard allows the first of those casts to produce a trap representation, and that it does not require the round-trip of int to void * to int to be value-preserving. That argument characterizes the C standard correctly, but it disregards the facts that as a practical matter, the casting approach works on substantially every C implementation that supports pthreads in the first place, and that it is common enough that an implementation on which it did not work reliably would have difficulty being accepted.

How to pass an int as "void *" to thread start function?

I originally had a global variable for my fibonacci variable array, but found out that is not allowed. I need to do elementary multithreading and handle race conditions, but I can't get past feeding an int as a void argument in pthread create. I've tried using a constant pointer with no luck. For some strange reason the void* gets past the first boolean test but not the else if:
$ gcc -o fibonacci fibonacci.c
fibonacci.c:22:16: warning: comparison between pointer and integer ('void *' and 'int')
else if (arg == 1)
~~~ ^ ~
1 warning generated.
My code is a mess and I am getting really confused because I have rewritten it so many times. If I cast all the args in my thread run function as ints I get a segmentation fault 11, which makes sense. All attempts at passing the i index by address and dereferencing it have failed, as it is a void and can't be used as an int. Can you suggest something else?
#include<stdio.h> //for printf
#include<stdlib.h> //for malloc
#include<pthread.h> //for threading
#define SIZE 25 //number of fibonaccis to be computed
int *fibResults; //array to store fibonacci results
void *run(void *arg) //executes and exits each thread
{
if (arg == 0)
{
fibResults[(int)arg] = 0;
printf("The fibonacci of %d= %d\n", (int)arg, fibResults[(int)arg]);
pthread_exit(0);
}
else if (arg == 1)
{
fibResults[(int)arg] = 1;
printf("The fibonacci of %d= %d\n", (int)arg, fibResults[(int)arg]);
pthread_exit(0);
}
else
{
fibResults[(int)arg] = fibResults[(int)arg -1] + fibResults[(int)arg -2];
printf("The fibonacci of %d= %d\n", (int)arg, fibResults[(int)arg]);
pthread_exit(0);
}
}
//main function that drives the program.
int main()
{
pthread_attr_t a;
fibResults = (int*)malloc (SIZE * sizeof(int));
pthread_attr_init(&a);
for (int i = 0; i < SIZE; i++)
{
pthread_t thread;
pthread_create(&thread, &a, run,(void*) &i);
printf("Thread[%d] created\t", i);
fflush(stdout);
pthread_join(thread, NULL);
printf("Thread[%d] joined & exited\t", i);
}
return 0;
}
You don't need the cast in the call to pthread_create() — the conversion to void * is automatic.
In the thread function, you could use
int i = *(int *)arg;
However, you've now got a synchronization problem; all the threads are using the same (pointer to the same) integer variable, and you can't predict which value they're going to see because of scheduling issues. The per-thread data needs to be 'per thread'.
So, there are various ways around that. In this context, I'd probably use
#include <stdint.h>
and in main():
pthread_create(&thread, &a, run, (void*)(uintptr_t)i);
and then in the thread function:
int i = (uintptr_t)arg;
Now the casts — the double cast even — is necessary. The cast to uintptr_t ensures the integer value is big enough to hold a pointer; the cast to void * is needed because there isn't an implicit cast from any integer type to void *. This ensures each thread function invocation has a different value. Sharing a pointer to an int means that everything is uncontrolled.
In the run() function you should do:
void *run(void *ptrarg) //executes and exits each thread
{
int arg = *((int *)ptrarg);
if (arg == 0)
....
....
and in rest of the run(), you don't need to cast the arg. Replace (int)arg with arg.
EDIT:
The way you are passing the argument to fun() while creating threads may cause race condition because all threads will be using same pointer. Check the #Jonathan's answer to avoid this problem.
#efuddy. Instead of (int)arg you should use (int *)arg to properly cast the **void pointer* void *arg

Avoiding race condition using int to void * casting [duplicate]

This question already has answers here:
Pass integer value through pthread_create
(4 answers)
Closed 5 years ago.
I am trying to understand following code. This code has no race conditions, but I cannot understand.
#include <stdio.h>
#include <pthread.h>
void *foo(void *vargp) {
int id;
id = (int)vargp;
printf("Thread %d\n", id);
}
int main() {
pthread_t tid[2];
int i;
for (i = 0; i < 2; i++)
pthread_create(&tid[i], NULL, foo, (void *)i);
pthread_join(tid[0], NULL);
pthread_join(tid[1], NULL);
return 0;
}
How does the typecasting from int to void* work?
The race condition that is avoided is illustrated by this code, which is very similar to the original code, but subtly different, and the difference makes it incorrect:
/* Incorrect code! */
#include <pthread.h>
#include <stdio.h>
static void *foo(void *vargp)
{
int id = *(int *)vargp;
printf("Thread %d\n", id);
return 0;
}
int main(void)
{
pthread_t tid[2];
int i;
for (i = 0; i < 2; i++)
pthread_create(&tid[i], NULL, foo, &i); // Bad idea!
pthread_join(tid[0], NULL);
pthread_join(tid[1], NULL);
return 0;
}
Since the function foo takes a void * argument, it seems logical to pass the address of the int to it. However, this has a major problem:
There is no guarantee which order the threads will execute, nor when, so there's no way to know which values the threads will see.
Indeed, when I ran this code the first time, both threads reported 2.
The way around this is to not pass the address of i but to pass i by value. However, the argument is still supposed to be a void *, so the code casts i to a void * before calling pthread_create(), and the thread function undoes the cast to retrieve the value.
When I'm doing this, I also use <stdint.h> to make the uintptr_t type available, and I use:
int id = (uintptr_t)vargp;
and
pthread_create(&tid[i], NULL, foo, (void *)(uintptr_t)i);
That looks excessive and/or obsessive, but the uintptr_t cast ensures the integer is the same size as a pointer to avoid the 'cast to pointer from integer of different size' compiler warning (which, since I tell the compiler to treat all warnings as errors, is necessary for me to get the code to compile at all).
If you do pass a pointer-to-data to the thread function (foo in this discussion), you must ensure that each thread you create gets its own copy of the data unless that data is meant to be identical in each thread.
You can see this technique at work in POSIX threads — unique execution.

pthread_create argument in c multi thread programming

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 .

pthread_join() and pthread_exit()

I have a question about C concurrency programming.
In the pthread library, the prototype of pthread_join is
int pthread_join(pthread_t tid, void **ret);
and the prototype of pthread_exit is:
void pthread_exit(void *ret);
So I am confused that, why pthread_join takes the return value of the process as a pointer to a void pointer from reaped thread, but pthread_exit only takes a void pointer from the exited thread? I mean basically they are all return values from a thread, why there is a difference in type?
In pthread_exit, ret is an input parameter. You are simply passing the address of a variable to the function.
In pthread_join, ret is an output parameter. You get back a value from the function. Such value can, for example, be set to NULL.
Long explanation:
In pthread_join, you get back the address passed to pthread_exit by the finished thread. If you pass just a plain pointer, it is passed by value so you can't change where it is pointing to. To be able to change the value of the pointer passed to pthread_join, it must be passed as a pointer itself, that is, a pointer to a pointer.
It because every time
void pthread_exit(void *ret);
will be called from thread function so which ever you want to return simply its pointer pass with pthread_exit().
Now at
int pthread_join(pthread_t tid, void **ret);
will be always called from where thread is created so here to accept that returned pointer you need double pointer ..
i think this code will help you to understand this
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <stdlib.h>
void* thread_function(void *ignoredInThisExample)
{
char *a = malloc(10);
strcpy(a,"hello world");
pthread_exit((void*)a);
}
int main()
{
pthread_t thread_id;
char *b;
pthread_create (&thread_id, NULL,&thread_function, NULL);
pthread_join(thread_id,(void**)&b); //here we are reciving one pointer
value so to use that we need double pointer
printf("b is %s\n",b);
free(b); // lets free the memory
}
The typical use is
void* ret = NULL;
pthread_t tid = something; /// change it suitably
if (pthread_join (tid, &ret))
handle_error();
// do something with the return value ret

Resources