Removing a printf statement affects the value of "i" in the loop where the program creates the child threads. I've tried printing a non-formatted string, and it breaks the program. Moving the printf above pthread_create() causes the same result. However, printing any formatted string after creating a thread will "fix" the program. Does anyone know what I've done wrong?
#include <stdio.h>
#include <pthread.h>
#define FALSE 0
#define TRUE !FALSE
pthread_mutex_t mutex;
pthread_cond_t cond1;
pthread_cond_t cond2;
int flag1 = FALSE;
int flag2 = FALSE;
void* someFunction(void* arg);
void anotherFunction(int threadNumber);
int main(int argc, char* argv[])
{
pthread_t threads[6];
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond1, NULL);
pthread_cond_init(&cond2, NULL);
for (int i = 0; i < 6; i )
{
// moving the printf to here will cause the program to hang
pthread_create(&threads[i], NULL, &someFunction, &i);
// not printing a formatted string here will cause the program to hang
printf("Thread %d created\n", i);
}
pthread_mutex_lock(&mutex);
for (int i = 0; i < 6; i )
{
flag1 = TRUE;
// go to child thread
pthread_cond_signal(&cond1);
// wait for child thread to change flag2
while (flag2 == FALSE)
{
pthread_cond_wait(&cond2, &mutex);
}
flag2 = FALSE;
pthread_mutex_unlock(&mutex);
}
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond1);
pthread_cond_destroy(&cond2);
return 0;
}
void* someFunction(void* arg)
{
int threadNumber = *(int*)arg;
pthread_mutex_lock(&mutex);
// wait for parent thread to change flag1
while (flag1 == FALSE)
{
pthread_cond_wait(&cond1, &mutex);
}
anotherFunction(threadNumber);
flag2 = TRUE;
// go back to parent thread
pthread_cond_signal(&cond2);
pthread_mutex_unlock(&mutex);
return NULL;
}
void anotherFunction(int threadNumber)
{
if (threadNumber == 0)
{
printf("I'm thread %d!\n", threadNumber);
}
else if (threadNumber == 1)
{
printf("I'm thread %d!\n", threadNumber);
}
else if (threadNumber == 2)
{
printf("I'm thread %d!\n", threadNumber);
}
else if (threadNumber == 3)
{
printf("I'm thread %d!\n", threadNumber);
}
else if (threadNumber == 4)
{
printf("I'm thread %d!\n", threadNumber);
}
else if (threadNumber == 5)
{
printf("I'm thread %d!\n", threadNumber);
}
}
This is the output when printing a formatted string.
Thread 0 created
Thread 1 created
Thread 2 created
Thread 3 created
Thread 4 created
Thread 5 created
I'm thread 0!
I'm thread 1!
I'm thread 2!
I'm thread 3!
I'm thread 4!
I'm thread 5!
This is the output when removing the printf
I'm thread 1!
I'm thread 2!
I'm thread 3!
I'm thread 4!
I'm thread 5!
The program just hangs after printing "I'm thread 5!".
EDIT: Thanks for the replies guys! Here is the solution
for (int i = 0; i < 6; i )
{
int* copy = malloc(sizeof(int));
*copy = i;
// moving the printf to here will cause the program to hang
pthread_create(&threads[i], NULL, &someFunction, copy);
// not printing a formatted string here will cause the program to hang
printf("Thread %d created\n", i);
}
CodePudding user response:
Here you pass the address of a local variable i
to the thread functions. This variable goes out of scope at least when the for
loop ends (or maybe even at the end of each iteration). This means every access to the variable by the threads after the end of the loop (or after the end of the loop iteration) is undefined behavior.
for (int i = 0; i < 6; i )
{
// moving the printf to here will cause the program to hang
pthread_create(&threads[i], NULL, &someFunction, &i);
// not printing a formatted string here will cause the program to hang
// printf("Thread %d created\n", i);
}
Your program will report this error when you compile the program with GCC using options -fsanitize=address -fsanitize=undefined
.
Even if you fix the scope of the variable, e.g. by moving it into function main
's scope, you pass the address of the same variable to all threads, so it is undefined which value (0..6) every thread may see. If the thread creation is faster than actually starting the thread, all threads might see the same value 6.
CodePudding user response:
Thanks for the replies guys! The solution was to dynamically allocate some memory for a copy of i
for (int i = 0; i < 6; i )
{
int* copy = malloc(sizeof(int));
*copy = i;
// moving the printf to here will cause the program to hang
pthread_create(&threads[i], NULL, &someFunction, copy);
// not printing a formatted string here will cause the program to hang
printf("Thread %d created\n", i);
}