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

如何用互斥量控制多线程启停:运行同一函数的线程阻塞唤醒问题

问题分析与修复方案

你的代码存在几个关键问题,导致条件变量无法正常实现线程的阻塞/唤醒控制,下面逐一拆解并给出修复方案:

核心错误点

  • 非法解锁互斥量:主线程初始化后直接调用pthread_mutex_unlock(&mtx),此时互斥量处于未锁定状态,这属于未定义行为,会破坏互斥量的内部状态,直接导致后续同步逻辑失效。
  • 缺少状态标志配合条件变量:条件变量不是单纯的"信号开关",必须搭配一个共享状态标志使用。没有状态标志的话,不仅会遭遇虚假唤醒,还无法让线程在完成一次运行后自动回到阻塞状态等待下一次指令。
  • 线程逻辑不完整:线程被唤醒后执行任务就解锁互斥量,后续循环重新加锁等待,但主线程没有明确的状态通知,线程无法正确感知何时需要再次阻塞。

修复后的代码

#include <pthread.h>
#include <stdio.h>
#include <unistd.h>

pthread_mutex_t mtx;
pthread_cond_t cv;
// 控制线程运行/阻塞的状态标志:1=允许运行,0=需要阻塞,2=线程退出
int run_flag = 0;

void* func(void* arg) {
    while (1) {
        pthread_mutex_lock(&mtx);
        // 循环等待,直到run_flag被设置为1(避免虚假唤醒)
        while (run_flag == 0) {
            pthread_cond_wait(&cv, &mtx);
        }
        
        // 检测退出信号
        if (run_flag == 2) {
            pthread_mutex_unlock(&mtx);
            break;
        }

        printf("Thread %lu is running.\n", pthread_self());
        
        // 任务执行完成后,重置标志为0,准备进入下一次阻塞
        run_flag = 0;
        pthread_mutex_unlock(&mtx);

        // 模拟线程工作(此处不需要持有锁)
        usleep(500000);
    }
    return NULL;
}

int main() {
    pthread_t threads[2];

    pthread_mutex_init(&mtx, NULL);
    pthread_cond_init(&cv, NULL);

    for (int i = 0; i < 2; ++i) {
        pthread_create(&threads[i], NULL, func, NULL);
    }

    // 第一次唤醒线程:设置标志+广播
    pthread_mutex_lock(&mtx);
    run_flag = 1;
    pthread_cond_broadcast(&cv);
    pthread_mutex_unlock(&mtx);
    sleep(2);

    // 等待线程完成当前任务并进入阻塞后,再次唤醒
    sleep(2);
    pthread_mutex_lock(&mtx);
    run_flag = 1;
    pthread_cond_broadcast(&cv);
    pthread_mutex_unlock(&mtx);
    sleep(2);

    // 通知线程退出,避免程序退出时线程仍在后台运行
    pthread_mutex_lock(&mtx);
    run_flag = 2;
    pthread_cond_broadcast(&cv);
    pthread_mutex_unlock(&mtx);

    // 等待所有线程退出
    for (int i = 0; i < 2; ++i) {
        pthread_join(threads[i], NULL);
    }

    pthread_mutex_destroy(&mtx);
    pthread_cond_destroy(&cv);

    return 0;
}

关键修改说明

  1. 添加run_flag状态标志:用这个变量明确传递主线程的控制指令,线程在pthread_cond_wait时循环检查标志,既确保只有主线程允许时才运行,也避免了虚假唤醒的干扰。
  2. 修正互斥量操作:主线程的锁操作严格配对,不再出现解锁未锁定互斥量的非法操作。
  3. 完善线程循环逻辑:线程执行完任务后主动重置run_flag为0,下一次循环会自动进入等待状态,无需额外操作。
  4. 添加线程终止逻辑:程序退出前设置特殊标志通知线程退出,避免线程处于无限循环导致程序无法正常终止。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 06:45:57