You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;
}

关键修改说明

  1. 共享状态变量current_thread:明确标记当前该执行的线程,所有线程通过这个变量判断自己是否可以执行,从根源上约束执行顺序。
  2. 单个互斥锁+条件变量:确保所有线程访问共享状态的原子性,避免竞态条件;用pthread_cond_broadcast唤醒所有等待线程,彻底解决信号丢失的问题。
  3. volatile修饰TRUE:禁止编译器对该变量做缓存优化,保证线程能及时读取到最新值,正常退出循环。
  4. 循环等待代替单次判断:用while(current_thread != X)包裹pthread_cond_wait,避免操作系统的虚假唤醒导致线程错误执行。

这样修改后,线程会严格按照你期望的顺序循环执行,不会再出现不稳定的情况。

内容的提问来源于stack exchange,提问作者張皓翔

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 19:12:39