如何让所有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
相关产品推荐
相关产品推荐

