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

如何让所有pthread线程等待其他线程全部启动后再执行?

实现线程同步等待所有线程就绪的无忙等待方案

你可以通过条件变量+互斥锁或信号量两种方式实现,完全避免忙等待,下面是具体实现:

方案一:条件变量+互斥锁(线程自主同步)

这种方式让线程之间互相等待,直到所有线程都进入就绪状态:

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

#define THREAD_NUM 4

// 同步变量:保护就绪计数的互斥锁、触发同步的条件变量、就绪线程计数
pthread_mutex_t ready_mutex;
pthread_cond_t ready_cond;
int ready_count = 0;

void *thread_routine(void *arg)
{
    pthread_mutex_lock(&ready_mutex);
    // 当前线程标记为就绪
    ready_count++;
    printf("线程 %ld 已就绪,当前就绪数:%d\n", pthread_self(), ready_count);

    // 最后一个就绪的线程唤醒所有等待的线程
    if (ready_count == THREAD_NUM) {
        pthread_cond_broadcast(&ready_cond);
    } else {
        // 未全部就绪则阻塞等待,pthread_cond_wait会自动释放互斥锁,避免占用CPU
        while (ready_count < THREAD_NUM) {
            pthread_cond_wait(&ready_cond, &ready_mutex);
        }
    }
    pthread_mutex_unlock(&ready_mutex);

    // 所有线程就绪后执行任务
    printf("线程 %ld 开始执行任务\n", pthread_self());
    // 此处编写具体任务逻辑

    return NULL;
}

int main(int argc, char *argv[])
{
    int i = 0;
    pthread_t thid[THREAD_NUM];

    // 初始化同步对象
    pthread_mutex_init(&ready_mutex, NULL);
    pthread_cond_init(&ready_cond, NULL);

    // 创建线程
    for (i = 0; i < THREAD_NUM; i++) {
        pthread_create(&thid[i], NULL, thread_routine, NULL);
    }

    // 等待所有线程结束
    for (i = 0; i < THREAD_NUM; i++) {
       pthread_join(thid[i], NULL);
    }

    // 销毁同步对象
    pthread_mutex_destroy(&ready_mutex);
    pthread_cond_destroy(&ready_cond);
    return 0;
}

方案说明

  • 互斥锁ready_mutex保护ready_count的修改,避免多线程下的竞态条件。
  • pthread_cond_wait会自动释放互斥锁并进入阻塞状态,完全没有忙等待的CPU消耗。
  • 最后一个完成就绪的线程通过pthread_cond_broadcast唤醒所有等待的线程,确保所有线程同时开始执行任务。

方案二:信号量(主线程协调同步)

这种方式由主线程负责确认所有线程就绪,再统一放行:

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

#define THREAD_NUM 4

// 就绪信号量:统计已就绪的线程数;放行信号量:控制线程开始执行
sem_t ready_sem;
sem_t start_sem;

void *thread_routine(void *arg)
{
    // 标记自身已就绪
    sem_post(&ready_sem);

    // 等待主线程的放行信号,阻塞期间不占用CPU
    sem_wait(&start_sem);

    // 执行任务
    printf("线程 %ld 开始执行任务\n", pthread_self());
    // 此处编写具体任务逻辑

    return NULL;
}

int main(int argc, char *argv[])
{
    int i = 0;
    pthread_t thid[THREAD_NUM];

    // 初始化信号量:ready_sem初始值0,start_sem初始值0
    sem_init(&ready_sem, 0, 0);
    sem_init(&start_sem, 0, 0);

    // 创建线程
    for (i = 0; i < THREAD_NUM; i++) {
        pthread_create(&thid[i], NULL, thread_routine, NULL);
    }

    // 主线程等待所有线程就绪
    for (i = 0; i < THREAD_NUM; i++) {
        sem_wait(&ready_sem);
    }
    printf("所有线程已就绪,开始执行任务\n");

    // 主线程放行所有线程
    for (i = 0; i < THREAD_NUM; i++) {
        sem_post(&start_sem);
    }

    // 等待所有线程结束
    for (i = 0; i < THREAD_NUM; i++) {
       pthread_join(thid[i], NULL);
    }

    // 销毁信号量
    sem_destroy(&ready_sem);
    sem_destroy(&start_sem);
    return 0;
}

方案说明

  • ready_sem用于主线程确认所有线程都已启动并到达等待点,每个线程就绪后调用sem_post,主线程通过sem_wait等待THREAD_NUM次。
  • start_sem用于主线程统一触发所有线程开始执行,主线程调用THREAD_NUM次sem_post,所有线程通过sem_wait接收放行信号。
  • 两种信号量的阻塞操作都不会占用CPU资源,完全避免忙等待。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 10:31:19