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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 13:05:44