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

