C语言中使用信号量排序线程事件遇乱序问题求助
问题分析与修复方案
你的信号量实现犯了两个核心错误,导致线程无法按顺序执行:
1. 信号量初始值设置错误
你给每个信号量的初始值都设为1,这意味着每个线程调用sem_wait(&s[i])时,都能直接获取到信号量(初始计数为1,sem_wait会将计数减为0,线程直接进入执行)。四个线程没有任何阻塞,自然会随机抢占CPU执行。
2. 同步逻辑完全不符合顺序执行的要求
每个线程只等待自己的信号量、执行后释放自己的信号量,完全没有建立线程之间的依赖关系。要实现顺序执行,线程必须等待前一个线程执行完成后发出的信号,而不是自己的信号量。
正确的实现思路
要让四个事件按event1 → event2 → event3 → event4的顺序执行,需要构建链式信号量依赖:
- 声明信号量数组
s[4],初始化时仅第一个信号量s[0]的初始值为1(允许第一个线程先执行),其余s[1]、s[2]、s[3]初始值为0(初始阻塞后续线程)。 - 每个线程执行完成后,释放下一个线程对应的信号量,通知其可以开始执行。
修正后的代码示例
线程函数调整
#include <semaphore.h> #include <pthread.h> #include <stdio.h> #include <unistd.h> sem_t s[4]; // 模拟事件执行的辅助函数 void make_event(int event_num) { sleep(1); printf("Event %d executed\n", event_num); } void *event1(void *arg) { sem_wait(&s[0]); // 获取第一个信号量,初始可获取 make_event(1); sem_post(&s[1]); // 通知event2可以执行 return NULL; } void *event2(void *arg) { sem_wait(&s[1]); // 等待event1的通知 make_event(2); sem_post(&s[2]); // 通知event3可以执行 return NULL; } void *event3(void *arg) { sem_wait(&s[2]); // 等待event2的通知 make_event(3); sem_post(&s[3]); // 通知event4可以执行 return NULL; } void *event4(void *arg) { sem_wait(&s[3]); // 等待event3的通知 make_event(4); // 最后一个线程无需post,除非要通知主线程 return NULL; }
main函数中的信号量初始化与线程创建
int main() { pthread_t threads[4]; // 初始化信号量:第二个参数为0表示线程共享(进程内) sem_init(&s[0], 0, 1); sem_init(&s[1], 0, 0); sem_init(&s[2], 0, 0); sem_init(&s[3], 0, 0); // 创建线程(顺序不影响,因为信号量会阻塞后续线程) pthread_create(&threads[0], NULL, event1, NULL); pthread_create(&threads[1], NULL, event2, NULL); pthread_create(&threads[2], NULL, event3, NULL); pthread_create(&threads[3], NULL, event4, NULL); // 等待所有线程完成 for (int i = 0; i < 4; i++) { pthread_join(threads[i], NULL); } // 销毁信号量 for (int i = 0; i < 4; i++) { sem_destroy(&s[i]); } return 0; }
为什么这样能生效?
- 初始状态只有
s[0]的计数为1,所以只有event1能通过sem_wait获取信号量并执行。 event1执行完成后调用sem_post(&s[1]),将s[1]的计数加为1,此时event2的sem_wait才能获取到信号量,开始执行。- 后续线程以此类推,严格按照
1→2→3→4的顺序依次执行,不会出现随机抢占的情况。
内容的提问来源于stack exchange,提问作者Louis Rollo
相关产品推荐
相关产品推荐

