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

Linux下C++线程无限等待问题排查:乒乓式通信代码故障

排查乒乓线程通信的死锁问题

让我来帮你揪出这个死锁的根源,顺便把代码修复好——你的问题主要出在条件变量的使用规范上,还有初始同步的小问题:

核心问题分析

  • 线程2违反条件变量的使用规则:pthread_cond_wait要求调用者必须先持有对应的互斥锁,否则会触发未定义行为。你的线程2直接在未加锁的情况下调用pthread_cond_wait(&dudum, &mut),这会导致线程间的同步完全混乱,大概率触发死锁。
  • 初始信号可能丢失:主线程启动两个线程后立刻发送dadam信号,但此时线程1可能还没进入pthread_cond_wait的等待状态,这个信号会直接丢失,导致线程1一直阻塞等待,线程2也会因为错误的等待逻辑卡住。
  • 缺少终止逻辑:原代码没有处理输入'e'或'E'的退出条件,会一直循环下去。

修复后的完整代码

#include <iostream>
#include <string>
#include <pthread.h>
#include <cctype> // 包含toupper的头文件
using namespace std;

pthread_mutex_t mut;
pthread_cond_t dadam; // 通知线程1可以输入
pthread_cond_t dudum; // 通知线程2可以处理
char x;
bool exit_flag = false; // 新增退出标记

void *first(void *arg) {
    while(1) {
        pthread_mutex_lock(&mut);
        // 等待线程2的通知(或者初始启动信号)
        pthread_cond_wait(&dadam, &mut);
        
        if (exit_flag) { // 检查是否需要退出
            pthread_mutex_unlock(&mut);
            break;
        }

        cout << "Type a letter (enter 'e' to exit):\n";
        cin >> x;

        // 检查是否触发退出条件
        if (tolower(x) == 'e') {
            exit_flag = true;
        }

        pthread_mutex_unlock(&mut);
        pthread_cond_signal(&dudum); // 通知线程2处理字符
    }
    return nullptr;
}

void *second(void *arg) {
    while(1) {
        pthread_mutex_lock(&mut); // 必须先加锁再调用wait
        pthread_cond_wait(&dudum, &mut);
        
        if (exit_flag) { // 检查退出标记
            pthread_mutex_unlock(&mut);
            break;
        }

        char y = toupper(x);
        cout << "Converted to uppercase: " << y << endl;

        pthread_mutex_unlock(&mut);
        pthread_cond_signal(&dadam); // 通知线程1继续输入
    }
    return nullptr;
}

int main() {
    // 初始化互斥锁和条件变量
    pthread_mutex_init(&mut, nullptr);
    pthread_cond_init(&dadam, nullptr);
    pthread_cond_init(&dudum, nullptr);

    pthread_t nun, nuno;
    pthread_create(&nun, nullptr, &first, nullptr);
    pthread_create(&nuno, nullptr, &second, nullptr);

    // 给线程1发送初始信号,让它开始第一次输入
    pthread_mutex_lock(&mut); // 加锁避免信号丢失
    pthread_cond_signal(&dadam);
    pthread_mutex_unlock(&mut);

    // 等待线程结束
    pthread_join(nun, nullptr);
    pthread_join(nuno, nullptr);

    // 清理资源
    pthread_mutex_destroy(&mut);
    pthread_cond_destroy(&dadam);
    pthread_cond_destroy(&dudum);

    return 0;
}

关键修改点说明

  1. 修正条件变量调用逻辑:线程2现在先调用pthread_mutex_lock,再调用pthread_cond_wait,完全符合POSIX线程的规范。
  2. 避免初始信号丢失:主线程发送初始信号前先加锁,确保线程1已经进入等待状态后再发送信号(或者至少保证信号不会因为竞态条件丢失)。
  3. 添加退出逻辑:新增exit_flag标记,当输入'e'或'E'时设置标记,让两个线程都能正常退出循环。
  4. 补充资源清理:原代码没有初始化和销毁互斥锁、条件变量,修复后补充了这些步骤,避免资源泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:29:42