C语言 不打印格式化字符串会影响多线程程序中变量的值



删除printf语句会影响"i"在程序创建子线程的循环中。我试过打印一个没有格式化的字符串,但是它破坏了程序。将printf移到pthread_create()之上会产生相同的结果。但是,在创建线程后打印任何格式化的字符串将"修复"。程序。有人知道我做错了什么吗?

#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 createdn", 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);
}
}

打印格式化字符串时的输出。

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!

这是删除printf

后的输出
I'm thread 1!
I'm thread 2!
I'm thread 3!
I'm thread 4!
I'm thread 5!

程序在打印"I'm thread 5!"后挂起。

编辑:谢谢你们的回复!以下是解决方案
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 createdn", i);
}

在这里,您将本地变量i的地址传递给线程函数。至少在for循环结束时(或者甚至在每次迭代结束时),该变量将超出作用域。这意味着线程在循环结束后(或循环迭代结束后)对变量的每次访问都是未定义的行为。

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 createdn", i);
}

当你用GCC使用选项-fsanitize=address -fsanitize=undefined编译程序时,你的程序会报告这个错误。

即使你修复了变量的作用域,例如通过将它移动到函数main的作用域,你将同一变量的地址传递给所有线程,因此每个线程可以看到的值(0..6)是未定义的。如果创建线程的速度比实际启动线程的速度快,那么所有线程可能看到相同的值。

(如注释中所述,由于数据竞争,您甚至可能看到其他值。如果在您的平台上对变量的访问是原子性的,或者如果循环只修改最低有效字节(如本例中),则通常会得到值0..6中的一个

谢谢大家的回复!解决方案是动态地为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 createdn", i);
}

最新更新