使用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
相关产品推荐
相关产品推荐

