I have this program:
void *func(void *arg) {
pthread_mutex_lock(&mutex);
int *id = (int *)arg;
printf("My ID is %d\n" , *id);
pthread_mutex_unlock(&mutex);
}
int main() {
int i;
pthread_t tid[3];
// Let us create three threads
for (i = 0; i < 3; i++) {
pthread_create(&tid[i], NULL, func, (void *)&i);
}
for (i = 0; i < 3; i++) {
pthread_join(tid[i], NULL);
}
pthread_exit(NULL);
return 0;
}
I expected it to output this:
My ID is 0
My ID is 1
My ID is 2
But instead I get random output, such as this:
My ID is 0
My ID is 0
My ID is 2
Since I already added mutex lock, I thought it would solve the problem. What else did I do wrong? Is this related to race condition?
Here id
points to the same variable i
in main for all the threads.
int *id = (int *)arg;
printf("My ID is %d\n" , *id);
But the variable i
is constantly being update by the two for
-loops in main
behind the threads back. So before the thread reaches the point of printf
, the value of i
, and therefore also the value of *id
, may have changed.
There are a few ways to solve this. The best way depends on the use case:
main
until the thread signals that it has made a copy of *id
before modifying i
or letting it go out of scope. int thread_id[]
, and create the threads like this: pthread_create(&tid[i], NULL, func, &thread_id[i]);
malloc
some memory and and initialize it with a copy of i
:
int *thread_id = malloc(sizeof(*thread_id)); *thread_id = i pthread_create(&tid[i], NULL, func, thread_id);
Just don't forget to free
your memory int the thread when you are finished using it. Or in main
if the thread fails to start.
If i
fits in a void *
can pass its content directly as a parameter to the thread. To make sure it fits, you can declare it as intptr_t
rather than int
(We basicly abuse the fact that pointers are nothing more than magic integers) :
void *func(void *arg) { pthread_mutex_lock(&mutex); // Here we interpret a pointer value as an integer value intptr_t id = (intptr_t )arg; printf("My ID is %d\\n" , (int)id); pthread_mutex_unlock(&mutex); } int main() { intptr_t i; pthread_t tid[3]; // Let us create three threads for (i = 0; i < 3; i++) { // Here we squeeze the integer value of `i` into something that is // supposed to hold a pointer pthread_create(&tid[i], NULL, func, (void *)i); } for (i = 0; i < 3; i++) { pthread_join(tid[i], NULL); } // This does not belong here !! // pthread_exit(NULL); return 0; }
Nope, no race conditions involved. (my b) There can be a race condition on i because all threads access it. Each thread gets started with a pointer to i. However, the main problem is that there is no guarantee that the thread will start and run the critical section while i holds the value you expect, in an order that you expect.
I'm assuming you declared the variable mutex
globally and called pthread_mutex_init()
somewhere to initialize it.
Mutexes are great to allow only one thread to access a critical section of code at a time. So the code as you've written creates all three threads to run in parallel, but only lets one thread at a time run the following code.
int *id = (int *)arg;
printf("My ID is %d\n" , *id);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.