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

使用pthread条件变量与临界区的C++死锁程序问题排查

问题排查与修复

核心问题分析

你的代码出现死锁主要有两个关键原因:

  1. 共享结构体的竞态覆盖
    所有线程共用同一个mainStruct实例,主线程在创建线程的循环中不断修改index和var。由于线程调度的不确定性,很多线程启动后读取到的index已经是主线程最后一次修改的值(比如线程0还没执行到读取index的步骤,主线程已经把index改成4了),导致线程的index与预期的编号不符,永远无法满足*turn == index的等待条件,陷入无限阻塞。

  2. 运算符优先级错误
    *workingVar->turn++;的执行顺序不符合预期:->的优先级高于*和++,实际是对turn指针本身做自增操作,而不是递增turn指向的变量。这会导致turn指针指向非法内存,后续线程读取*turn的值完全错误,无法正确推进执行顺序。


修复后的代码

#include <iostream>
#include <pthread.h>

using namespace std;

struct foo
{
public:
    int var;
    int *turn;
    int index;
    pthread_mutex_t *bsem;
    pthread_cond_t *waitTurn;
};

void *threadFunc(void *arg) {
    int var;
    foo *workingVar = static_cast<foo*>(arg);

    pthread_mutex_lock(workingVar->bsem);
    while (*workingVar->turn != workingVar->index) {
        pthread_cond_wait(workingVar->waitTurn, workingVar->bsem);
    }
    var = workingVar->var;
    (*workingVar->turn)++; // 修正运算符优先级,递增turn指向的变量
    pthread_cond_broadcast(workingVar->waitTurn);
    pthread_mutex_unlock(workingVar->bsem);

    cout << var << endl;
    return nullptr;
}

int main() {
    int turn = 0;
    const int NTHREADS = 5;
    pthread_mutex_t bsem;
    pthread_mutex_init(&bsem, NULL);
    pthread_cond_t waitTurn = PTHREAD_COND_INITIALIZER;

    // 为每个线程分配独立的结构体实例,避免主线程修改覆盖
    foo threadStructs[NTHREADS];
    pthread_t tid[NTHREADS];

    for (int i = 0; i < NTHREADS; i++) {
        threadStructs[i].var = i;
        threadStructs[i].index = i;
        threadStructs[i].turn = &turn;
        threadStructs[i].bsem = &bsem;
        threadStructs[i].waitTurn = &waitTurn;
        pthread_create(&tid[i], nullptr, threadFunc, &threadStructs[i]);
    }

    for (int i = 0; i < NTHREADS; i++) {
        pthread_join(tid[i], NULL);
    }

    // 清理同步资源
    pthread_mutex_destroy(&bsem);
    pthread_cond_destroy(&waitTurn);
    return 0;
}

关键修改点说明

  • 为每个线程创建独立的foo结构体实例(threadStructs数组),确保每个线程读取的index和var是创建时的固定值,不会被主线程后续修改覆盖。
  • 修正turn递增的写法为(*workingVar->turn)++,明确先解引用获取turn指向的变量,再递增其值。
  • 使用static_cast替代C风格强制转换,符合C++类型安全规范。
  • 添加同步资源的销毁操作,避免内存泄漏。

内容的提问来源于stack exchange,提问作者KilometerP

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 15:45:43