How can I pass the index of a for loop as the argument for pthread_create
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++ ormalloc
in C) space for a singleint
, 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 throughuintptr_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;
You've made this a little too complicated:
for (int i = 0; i < count; i++){
pthread_create(&p[i], NULL, &somefunc, (void*)&i);
You just want to pass the value, not a pointer to it, so pass (void*)i
. As is, you're passing each thread a pointer to i
which has problems:
i
will likely have left scope by the time the thread tries to read from its address - some other variable might be there instead or the memory might be sitting around unused with who-knows-what left in it- the next iteration in the loop will overwrite the value anyway, which means all threads would be likely to see the value "count" when they dereference the pointer, if it hadn't been clobbered as above, and except for rare cases where the launching thread is suspended during looping allowing a thread it spawned to read some earlier
i
value
So:
for (int i = 0; i < count; i++){
pthread_create(&p[i], NULL, &somefunc, (void*)i);
...
void *somefunc (void* id_cast_to_voidptr){
int id = (int)id_cast_to_voidptr;
}