I am using a for loop to create a number of threads and passing the index i as an argument as follows:
pthread_t p[count];
for (int i = 0; i < count; i++){
pthread_create(&p[i], NULL, &somefunc, (void*)&i);
}
Then I attempt to retrieve the value of i:
void *somefunc (void* ptr){
int id = *(int*)ptr;
}
However, I noticed that sometimes, id in the threads will have overlapping values which I suspect is due to the index of the for loop updating before the thread is able to retrieve the value (since I passed in the pointer, as opposed to the value itself). Does anyone have any suggestions to overcome this issue without slowing down the for loop?
Thanks
Example 1 - Thread Argument Passing long taskids[NUM_THREADS]; for(t=0; t<NUM_THREADS; t++) { taskids[t] = t; printf("Creating thread %ld\n", t); rc = pthread_create(&threads[t], NULL, PrintHello, (void *) taskids[t]); ... }
The last parameter of pthread_create() is passed as the argument to the function, whereas the return value is passed using pthread_exit() and pthread_join() .
On success, pthread_create() returns 0; on error, it returns an error number, and the contents of *thread are undefined.
pthread_t is the data type used to uniquely identify a thread. It is returned by pthread_create() and used by the application in function calls that require a thread identifier. The thread is created running start_routine, with arg as the only argument.
This is happening because once you pass a pointer to i
you now have multiple threads using the same value. This causes a data race because the first thread is modifying i
and your second thread is expecting it to never change. You can always allocate a temporary int and pass it to the thread function.
pthread_create(&p[i], NULL, &somefunc, new int(i));
This will allocate an integer in dynamic storage (heap) and initialize it with the value of i
. A pointer to the newly allocated integer will then be passed to the thread function.
Then in the thread function you can take the value passed as you already do and then delete the int object.
void *somefunc (void* ptr){
int id = *(int*)ptr;
delete (int*)ptr;
}
[Suggestion: Avoid C style casts.]
As others have said, you're passing a pointer to an object that's being modified by another thread (the parent) and accessing it without any synchronization. This is an error.
There are at least 3 solutions:
Allocate (via new
in C++ or malloc
in C) space for a single int
, and have the new thread be responsible for freeing it. This is probably the worst solution because now you have an extra failure case to handle (failure to allocate) and thus it complicates and clutters your code.
Cast the integer to void *
and back. This will surely work on any real-world POSIX system, but it's not "guaranteed" to work, and perhaps more annoyingly, it may incur warnings. You can avoid the warnings with an intermediate cast through uintptr_t
.
Instead of passing an index, pass an address:
pthread_create(&p[i], NULL, &somefunc, &p[i]);
Then the start function can recover the index (if it needs it for anything) by subtracting p
:
int id = (pthread_t *)ptr - p;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With