Hi I have a question about pthreads
I am repeatedly testing pthread_create and pthread_join, but it seems that the argument values passed to the function are not being passed properly
However, if I put the sleep() code after pthread_create, it works well
I don't know why it works, Is the sleep function really necessary?
Code:
#include <unistd.h>
#include <stdio.h>
#include <pthread.h>
void *thread_func(void *arg)
{
printf("I am thread #%d\n", *(int *)arg);
}
int main(int argc, char *argv[])
{
pthread_t t1[7];
while(1){
for(int i = 0; i < 7; i++){
pthread_create(&t1[i], NULL, &thread_func, &i);
}
sleep(10);
for(int j = 0; j < 7; j++){
pthread_join(t1[j], NULL);
}
sleep(10);
}
return 0;
}
int main(int argc, char *argv[])
{
pthread_t t1[7];
while(1){
for(int i = 0; i < 7; i++){
pthread_create(&t1[i], NULL, &thread_func, &i);
usleep(1);
}
sleep(10);
for(int j = 0; j < 7; j++){
pthread_join(t1[j], NULL);
}
sleep(10);
}
return 0;
}
I am repeatedly testing pthread_create and pthread_join, but it seems that the argument values passed to the function are not being passed properly
Doubtful.
However, if I put the sleep() code after pthread_create, it works well
I don't know why it works, Is the sleep function really necessary?
Calling sleep()
is a workaround to the real problem. It is not necessary in the sense that if your program's undefined behavior were satisfactorily resolved, then it would produce the wanted results whether or not sleep()
was called.
The issue is that when you pass &i
as the last argument to pthread_create()
, you create a situation where the original thread and the new one are both looking at the same int
object, and the original thread is also modifying that object as it processes successive loop iterations. Ultimately, the lifetime of that loop-scoped object ends when the loop terminates. There being no suitable synchronization between your threads, the behavior of your program is undefined. Your threads could print any thread numbers at all, or your program could crash, or in principle, anything at all within the computer's capabilities could happen.
Possible solutions include:
int
object. For example,
int args[7];
for (int i = 0; i < 7; i++){
args[i] = i;
pthread_create(&t1[i], NULL, &thread_func, &args[i]);
}
i
instead of a pointer to i
:
for (int i = 0; i < 7; i++){
pthread_create(&t1[i], NULL, &thread_func, (void *) i);
}
The thread function will then need to convert it back appropriately:
printf("I am thread #%d\n", (int) arg);
i
before the new thread has had a chance to read it. A semaphore would be convenient, though there are other possibilities:
sem_t startup_sem;
// ...
int main(int argc, char *argv[]) {
sem_init(&startup_sem, 0, 0);
// ...
for(int i = 0; i < 7; i++){
pthread_create(&t1[i], NULL, &thread_func, &i);
sem_wait(&startup_sem);
}
// ...
Meanwhile, the thread function increments the semaphore when it is ready for the main thread to proceed. Maybe like this:
void *thread_func(void *arg) {
int i = *(void *)arg;
sem_post(&startup_sem);
printf("I am thread #%d\n", i);
}