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

使用CreateSemaphore()信号量能否实现线程等待前一线程执行完毕

问题原因

你当前代码出现第一个线程连续多次运行的问题,核心出在两个设计错误:

  • 仅使用1个初始计数为1的信号量,这个信号量只起到互斥锁的作用,只能保证同一时间只有一个线程进入临界区,完全无法控制线程的执行顺序。当add线程释放信号量后,add和sub两个线程会同时竞争信号量所有权,Windows线程调度不保证等待队列严格先到先得,很容易出现add线程刚释放就立刻抢到信号量重复执行的情况。
  • 你用来做执行标记的全局变量asFlag是普通bool类型,跨线程读写时没有做任何原子保护或内存同步,编译器重排、CPU缓存都会导致sub线程无法及时读到asFlag的修改,持续读到旧值true,进一步加剧第一个线程重复运行的问题。
  • 额外存在逻辑bug:两个线程都是while(true)死循环,没有退出逻辑,WaitForMultipleObjects会永久阻塞无法返回。另外你给WaitForSingleObject传入的超时时间是INFINITE,永远不会返回WAIT_TIMEOUT状态,对应的错误处理代码完全无效。
纯信号量实现顺序执行的方案

不需要额外标志位,使用两个信号量分别作为两个线程的运行许可,就可以严格控制执行顺序,核心逻辑:

  • 给add线程分配专属信号量,初始计数设为1,保证程序启动后add线程第一个执行
  • 给sub线程分配专属信号量,初始计数设为0,程序启动后sub线程直接阻塞,不会参与资源竞争
  • 每个线程执行完自身逻辑后,只释放对方线程的信号量,不释放自身的运行许可,从根源上避免自己重复抢到执行权的问题

修正后的可运行代码如下:

#include <stdio.h>
#include <Windows.h>
#include <process.h>

HANDLE hSemAdd;
HANDLE hSemSub;
HANDLE hThreads[2];
int i = 0;
const int MAX_RUN_COUNT = 10; // 控制交替执行次数,避免死循环

unsigned int __stdcall addthread(void* data)
{
    for (int cnt = 0; cnt < MAX_RUN_COUNT; cnt++)
    {
        WaitForSingleObject(hSemAdd, INFINITE);
        i += 5;
        printf("add: %d\n", i);
        ReleaseSemaphore(hSemSub, 1, NULL); // 执行完只给sub线程发许可
    }
    return 0;
}

unsigned int __stdcall subthread(void* data)
{
    for (int cnt = 0; cnt < MAX_RUN_COUNT; cnt++)
    {
        WaitForSingleObject(hSemSub, INFINITE);
        i -= 5;
        printf("sub: %d\n", i);
        ReleaseSemaphore(hSemAdd, 1, NULL); // 执行完只给add线程发许可
    }
    return 0;
}

int main()
{
    printf("Original Number: %d\n", i);
    // 创建两个信号量
    hSemAdd = CreateSemaphore(NULL, 1, 1, NULL);
    hSemSub = CreateSemaphore(NULL, 0, 1, NULL);

    if (!hSemAdd || !hSemSub)
    {
        printf("Semaphore Create Fail\n");
        return 1;
    }

    hThreads[0] = (HANDLE)_beginthreadex(NULL, 0, addthread, NULL, 0, NULL);
    hThreads[1] = (HANDLE)_beginthreadex(NULL, 0, subthread, NULL, 0, NULL);

    WaitForMultipleObjects(2, hThreads, TRUE, INFINITE);

    // 关闭句柄
    CloseHandle(hThreads[0]);
    CloseHandle(hThreads[1]);
    CloseHandle(hSemAdd);
    CloseHandle(hSemSub);

    system("pause");
    return 0;
}

运行后输出会严格按照add:5→sub:0→add:5→sub:0的顺序交替,不会出现同一个线程连续执行的情况。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 10:15:30