多线程程序异常求助:仅单线程工作或无线程运行问题排查
多线程全局变量操作问题排查与解决
嘿,我来帮你排查这个多线程问题!这种单个线程执行甚至都不工作的情况,大概率是同步、可见性或者线程调度的问题,我结合常见的类似场景给你分析下:
常见问题原因分析
- 主线程提前退出:如果你的
main函数创建完线程后直接返回,整个进程会立刻终止,子线程可能还没来得及执行就被销毁了,这就是为啥有时两个线程都没动静的原因。 - 竞态条件与无同步机制:两个线程同时读写全局变量时,会出现“判断-操作”的原子性问题——比如求和线程刚判断完
count≤5,还没执行加1,减线程已经把count改成了>5,导致逻辑混乱;或者反过来,减线程判断时count>5,但求和线程已经把它改回≤5了。 - 变量可见性问题:如果全局变量没加
volatile修饰,编译器可能会把变量缓存到寄存器里,线程看不到其他线程对变量的修改,比如求和线程一直用寄存器里的旧值判断count≤5,一直循环加,而减线程却一直看不到count已经超过5,完全不执行。
假设你的错误代码示例(常见场景)
#include <stdio.h> #include <pthread.h> // 两个全局变量,这里假设是count和无同步的控制逻辑 int count = 0; // 可能你还有另一个全局变量,比如flag,但核心问题还是同步 void* sum(void* arg) { while (count <= 5) { count++; printf("Sum thread: count = %d\n", count); } return NULL; } void* sub(void* arg) { while (count > 5) { count--; printf("Sub thread: count = %d\n", count); } return NULL; } int main() { pthread_t t1, t2; pthread_create(&t1, NULL, sum, NULL); pthread_create(&t2, NULL, sub, NULL); // 没有等待子线程,直接退出 return 0; }
修复后的代码与解释
下面是修复后的代码,我标注了关键修复点:
#include <stdio.h> #include <pthread.h> #include <unistd.h> // 1. 用volatile保证变量可见性,线程每次读取内存中的最新值 volatile int count = 0; // 2. 用互斥锁保证对全局变量的操作是原子的 pthread_mutex_t mutex; void* sum(void* arg) { while (1) { pthread_mutex_lock(&mutex); // 3. 在锁内做条件判断,确保判断和操作的原子性 if (count > 5) { pthread_mutex_unlock(&mutex); break; } count++; printf("Sum thread: count = %d\n", count); pthread_mutex_unlock(&mutex); // 4. 主动让出CPU,给另一个线程执行机会 usleep(100000); } return NULL; } void* sub(void* arg) { while (1) { pthread_mutex_lock(&mutex); if (count <= 5) { pthread_mutex_unlock(&mutex); break; } count--; printf("Sub thread: count = %d\n", count); pthread_mutex_unlock(&mutex); usleep(100000); } return NULL; } int main() { pthread_t t1, t2; // 初始化互斥锁 pthread_mutex_init(&mutex, NULL); pthread_create(&t1, NULL, sum, NULL); pthread_create(&t2, NULL, sub, NULL); // 5. 等待两个子线程执行完毕,避免主线程提前退出 pthread_join(t1, NULL); pthread_join(t2, NULL); // 销毁互斥锁 pthread_mutex_destroy(&mutex); return 0; }
关键修复点说明
- 互斥锁:确保同一时间只有一个线程能读写
count,彻底解决竞态条件。 - volatile修饰:防止编译器优化,保证线程能看到其他线程对变量的修改。
- pthread_join等待:让主线程等待子线程完成后再退出,确保子线程有足够时间执行。
- 锁内条件判断:把“判断-修改”放在锁内,避免判断后变量被其他线程修改,导致逻辑错误。
- 主动让出CPU:用
usleep让线程暂时休眠,给另一个线程执行机会,避免单个线程长期占用CPU。
预期输出示例
Sum thread: count = 1 Sum thread: count = 2 Sum thread: count = 3 Sum thread: count = 4 Sum thread: count = 5 Sum thread: count = 6 Sub thread: count = 5 Sub thread: count = 4 Sub thread: count = 3 Sub thread: count = 2 Sub thread: count = 1 Sub thread: count = 0
内容的提问来源于stack exchange,提问作者Cristian Nicolae Lupascu
相关产品推荐
相关产品推荐

