Ubuntu16.04下Pthreads指定执行顺序失效问题排查
问题原因分析与解决方案
你的线程执行顺序不稳定,主要是由以下几个核心问题导致的:
1. 多组独立互斥锁+条件变量的设计缺陷
你为每个线程单独分配了互斥锁(lock1/lock2/lock3)和条件变量(cond1/cond2/cond3),这种设计完全无法保证线程间的同步约束:
- 操作系统的线程调度是无序的,比如
thread3可能在thread1发送cond3信号后,还没进入pthread_cond_wait的等待状态,这时信号会直接丢失,导致thread3永远阻塞,后续的执行链条(thread3→thread2→thread1)直接断裂。 - 独立的互斥锁意味着线程之间没有共享的同步状态,无法准确判断「当前该哪个线程执行」,完全依赖不可靠的信号传递。
2. 全局变量TRUE未加volatile修饰
TRUE是控制线程循环退出的开关,但你没有用volatile修饰它。编译器会对非volatile的全局变量做缓存优化,将其存入线程的寄存器中,导致线程无法及时感知到TRUE被修改为0的变化,可能出现无法正常退出的情况。
3. 线程初始化打印顺序无保证
pthread_create成功后,线程何时被调度执行由操作系统决定,所以In thread1/In thread2/In thread3的打印顺序本身就无法保证,这属于正常的调度行为,但如果你的业务逻辑依赖这个初始顺序,也需要额外同步。
修复后的代码
我们改用单个互斥锁+单个条件变量+共享状态变量的方案,严格控制线程按thread1→thread3→thread2的顺序循环执行:
#include<pthread.h> #include<stdio.h> #include<stdlib.h> #include<unistd.h> #include <signal.h> // 共享状态:标记当前该执行的线程,1=thread1,2=thread2,3=thread3 int current_thread = 1; // 单个互斥锁和条件变量,统一同步所有线程 pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t cond = PTHREAD_COND_INITIALIZER; // volatile修饰,确保线程能及时感知变量变化 volatile int TRUE = 1; void * threadMethod1(void *arg) { printf("In thread1\n"); do{ pthread_mutex_lock(&lock); // 循环等待直到轮到自己执行,避免虚假唤醒 while(current_thread != 1) { pthread_cond_wait(&cond, &lock); } // 业务逻辑:打印报告 printf("I am thread1 generating the final report and inserting into a table \n"); // 更新状态为下一个要执行的线程:thread1之后是thread3 current_thread = 3; // 唤醒所有等待的线程,让它们检查状态 pthread_cond_broadcast(&cond); pthread_mutex_unlock(&lock); }while(TRUE); pthread_exit(NULL); } void * threadMethod2(void *arg) { printf("In thread2\n"); do { pthread_mutex_lock(&lock); while(current_thread != 2) { pthread_cond_wait(&cond, &lock); } printf("I am thread2 generating the final report and inserting into a table \n"); // thread2之后回到thread1,形成循环 current_thread = 1; pthread_cond_broadcast(&cond); pthread_mutex_unlock(&lock); }while(TRUE); pthread_exit(NULL); } void * threadMethod3(void *arg) { printf("In thread3\n"); do { pthread_mutex_lock(&lock); while(current_thread != 3) { pthread_cond_wait(&cond, &lock); } printf("I am thread3 generating the final report and inserting into a table \n"); // thread3之后是thread2 current_thread = 2; pthread_cond_broadcast(&cond); pthread_mutex_unlock(&lock); }while(TRUE); pthread_exit(NULL); } void my_alarm_handler(int a) { TRUE = 0;// 触发线程退出 } int main(void) { pthread_t tid1, tid2, tid3; signal( SIGALRM, my_alarm_handler ); printf("Before creating the threads\n"); if( pthread_create(&tid1, NULL, threadMethod1, NULL) != 0 ) printf("Failed to create thread1\n"); if( pthread_create(&tid2, NULL, threadMethod2, NULL) != 0 ) printf("Failed to create thread2\n"); if( pthread_create(&tid3, NULL, threadMethod3, NULL) != 0 ) printf("Failed to create thread3\n"); // 给线程一点时间完成初始化打印,不需要的话可以删除 usleep(100000); printf("!!!!!!!!!!!!!!!!!!\n"); alarm(1); pthread_join(tid1,NULL); pthread_join(tid2,NULL); pthread_join(tid3,NULL); // 清理同步资源 pthread_mutex_destroy(&lock); pthread_cond_destroy(&cond); return 0; }
关键修改说明
- 共享状态变量
current_thread:明确标记当前该执行的线程,所有线程通过这个变量判断自己是否可以执行,从根源上约束执行顺序。 - 单个互斥锁+条件变量:确保所有线程访问共享状态的原子性,避免竞态条件;用
pthread_cond_broadcast唤醒所有等待线程,彻底解决信号丢失的问题。 volatile修饰TRUE:禁止编译器对该变量做缓存优化,保证线程能及时读取到最新值,正常退出循环。- 循环等待代替单次判断:用
while(current_thread != X)包裹pthread_cond_wait,避免操作系统的虚假唤醒导致线程错误执行。
这样修改后,线程会严格按照你期望的顺序循环执行,不会再出现不稳定的情况。
内容的提问来源于stack exchange,提问作者張皓翔
相关产品推荐
相关产品推荐

