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

Win Socket API多线程任务序列同步:单/双信号量选择问题

问题解答:用双信号量实现线程顺序执行

核心结论

要实现 task_A → task_B → task_C → task_D 的固定执行顺序,必须使用两个信号量。单个信号量只能实现简单互斥,无法精准控制多步骤的线程依赖顺序。

你的单个信号量实现问题分析

你当前的代码仅第一次符合预期,后续出现乱序的原因是:

  • 第一次循环:Thread_A先抢占信号量执行task_A,释放后Thread_B拿到信号量执行task_B+task_C,释放后Thread_A再拿到信号量执行task_D,流程正常。
  • 第二次循环:Thread_A释放task_D对应的信号量后,Thread_B可能立刻抢占信号量,直接执行task_B+task_C,而Thread_A还没开始下一轮的task_A,最终导致B、C、A、B的错误顺序。
    单个信号量只能保证同一时刻只有一个线程执行临界区,但无法指定线程的执行先后顺序。

正确的双信号量实现(Win32 API环境)

1. 信号量初始化

首先创建两个初始值为0的信号量,分别控制不同步骤的依赖:

// 控制Thread_B等待Thread_A完成task_A
HANDLE sem_A_to_B = CreateSemaphore(NULL, 0, 1, NULL);
// 控制Thread_A等待Thread_B完成task_C
HANDLE sem_C_to_D = CreateSemaphore(NULL, 0, 1, NULL);

2. Thread_A逻辑

DWORD WINAPI Thread_A(LPVOID lpParam) {
    while (1) {
        // 执行task_A
        printf("print task_A\n");
        
        // 通知Thread_B可以执行task_B
        ReleaseSemaphore(sem_A_to_B, 1, NULL);
        
        // 等待Thread_B完成task_C
        WaitForSingleObject(sem_C_to_D, INFINITE);
        
        // 执行task_D
        printf("print task_D\n");
    }
    return 0;
}

3. Thread_B逻辑

DWORD WINAPI Thread_B(LPVOID lpParam) {
    while (1) {
        // 等待Thread_A完成task_A
        WaitForSingleObject(sem_A_to_B, INFINITE);
        
        // 执行task_B
        printf("print task_B\n");
        // 执行task_C
        printf("print task_C\n");
        
        // 通知Thread_A可以执行task_D
        ReleaseSemaphore(sem_C_to_D, 1, NULL);
    }
    return 0;
}

实现原理

  • sem_A_to_B 初始为0,Thread_B启动后会卡在WaitForSingleObject,直到Thread_A执行完task_A并释放该信号量,确保task_A一定在task_B之前执行。
  • sem_C_to_D 初始为0,Thread_A执行完task_A后会卡在WaitForSingleObject,直到Thread_B执行完task_C并释放该信号量,确保task_C一定在task_D之前执行。
  • 每次循环都会严格遵循A→B→C→D的顺序,不会出现乱序问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 09:10:00