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

Pthread多线程优化:4个工作线程完成后唤醒休眠线程的更佳方案

问题与优化方案:Pthread多线程任务同步

原问题场景

使用C++ pthread实现4个工作线程,要求所有工作线程完成任务后唤醒休眠线程。当前采用条件等待实现,但效果不佳。原流程为:广播触发4个任务并行执行,每个任务结束后设置对应flag为1,并向休眠线程发送信号;休眠线程被唤醒后检查所有flag,全为1则执行自身逻辑。

原代码存在的问题

  1. 共享变量无锁访问:flag_task的读写未加互斥锁,存在竞态条件,可能导致休眠线程读取到不一致的状态。
  2. 不必要的频繁唤醒:每个工作线程完成后都发送pthread_cond_signal,导致休眠线程被多次唤醒,每次都要遍历检查4个flag,效率低下。
  3. 条件变量使用不规范:工作线程各自持有独立的mutex[taskID],却共用同一个cond,违反pthread条件变量的使用规范,可能引发未定义行为。
  4. 无法支持多轮任务:休眠线程仅执行一次任务处理就退出,无法匹配工作线程的while(1)循环逻辑,无法处理后续任务轮次。

优化实现方案

核心优化点

  • 用完成任务计数替代多个flag,简化状态管理,减少竞态点。
  • 所有共享变量的读写操作必须在互斥锁保护下进行。
  • 仅当最后一个任务完成时才发送唤醒信号,避免多余的线程唤醒。
  • 统一工作线程的条件变量与互斥锁,符合pthread规范。
  • 支持多轮任务循环执行,匹配工作线程的持续运行逻辑。

优化后代码

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

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond_work = PTHREAD_COND_INITIALIZER;   // 触发工作线程的条件变量
pthread_cond_t cond_sleep = PTHREAD_COND_INITIALIZER;  // 唤醒休眠线程的条件变量
int completed_tasks = 0;                               // 已完成任务计数
int task_round = 0;                                    // 当前任务轮次,避免虚假唤醒

void *thread_sleep(void *arg) {
    pthread_mutex_lock(&mutex);
    while (1) {
        // 等待当前轮次所有任务完成
        while (completed_tasks < 4) {
            pthread_cond_wait(&cond_sleep, &mutex);
        }

        // 执行休眠线程的核心工作
        printf("[休眠线程] 所有工作线程完成第%d轮任务,开始执行自身逻辑\n", task_round);

        // 重置状态,准备下一轮任务
        completed_tasks = 0;
        task_round++;
        // 广播唤醒工作线程开始下一轮任务
        pthread_cond_broadcast(&cond_work);
    }
    pthread_mutex_unlock(&mutex);
    return NULL;
}

void *thread(void *arg) {
    int taskID = *(char *)arg - '0';
    int current_round = 0;

    pthread_mutex_lock(&mutex);
    while (1) {
        // 等待当前轮次的任务触发
        while (task_round == current_round) {
            pthread_cond_wait(&cond_work, &mutex);
        }
        current_round = task_round;
        pthread_mutex_unlock(&mutex);

        // 执行工作线程的任务逻辑(无需持有锁)
        printf("[工作线程%d] 开始执行第%d轮任务\n", taskID, current_round);
        // 模拟任务执行耗时
        sleep(1);

        pthread_mutex_lock(&mutex);
        completed_tasks++;
        // 仅最后一个完成任务的线程发送唤醒信号
        if (completed_tasks == 4) {
            pthread_cond_signal(&cond_sleep);
        }
    }
    pthread_mutex_unlock(&mutex);
    return NULL;
}

int main() {
    pthread_t pthread1, pthread2, pthread3, pthread4, pthread5;

    pthread_create(&pthread1, NULL, thread, (void *)"0");
    pthread_create(&pthread2, NULL, thread, (void *)"1");
    pthread_create(&pthread3, NULL, thread, (void *)"2");
    pthread_create(&pthread4, NULL, thread, (void *)"3");
    pthread_create(&pthread5, NULL, thread_sleep, (void *)"4");

    // 触发第一轮任务
    pthread_mutex_lock(&mutex);
    task_round++;
    pthread_cond_broadcast(&cond_work);
    pthread_mutex_unlock(&mutex);

    // 示例:等待线程结束(实际可根据需求设置退出机制)
    pthread_join(pthread1, NULL);
    pthread_join(pthread2, NULL);
    pthread_join(pthread3, NULL);
    pthread_join(pthread4, NULL);
    pthread_join(pthread5, NULL);

    return 0;
}

方案说明

  1. 计数替代flag:用completed_tasks记录已完成的任务数,简化状态检查逻辑,减少共享变量的维护成本。
  2. 锁保护共享变量:所有对completed_tasks和task_round的读写都在互斥锁mutex的保护下,避免竞态条件。
  3. 精准唤醒:只有当completed_tasks达到4时(即最后一个任务完成),才发送pthread_cond_signal,避免休眠线程被多次唤醒。
  4. 规范的条件变量使用:工作线程共用同一个cond_work和mutex,符合pthread条件变量的使用要求,避免未定义行为。
  5. 多轮任务支持:通过task_round标记任务轮次,休眠线程完成当前工作后重置状态并唤醒工作线程,实现持续的任务循环。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 09:10:44