Windows C中如何基于主线程条件正确关闭/退出子线程?
问题分析
你的代码存在几个关键问题导致子线程无法被正确终止:
- 子线程的
while(1)死循环未检查ts.running状态,主线程修改标志后子线程完全无响应 CloseHandle(volume_h_thread)仅关闭线程句柄,不会终止线程执行;ExitThread是线程自我终止的函数,不能用来终止其他线程- 子线程里的
Sleep(SLEEP_TIME)是阻塞调用,就算状态改变,也要等Sleep结束才会检查,无法及时响应启停命令
修正方案
我们用事件对象配合状态标志实现线程的优雅启停,让子线程能及时响应终止信号:
- 创建手动重置事件,用于通知子线程退出
- 子线程用
WaitForSingleObject替代Sleep,既实现定时,又能被事件中断 - 主线程通过触发事件通知子线程终止,等待线程退出后再重新创建新线程
修正后的完整代码
#include <stdio.h> #include <windows.h> #define SLEEP_TIME 5000 // 5 seconds // 全局事件:用于通知子线程退出 HANDLE hExitEvent = NULL; // 线程运行状态标志 BOOL g_threadRunning = TRUE; DWORD WINAPI volume_loop(void *data) { unsigned int times_pressed = 0; INPUT ip; ip.type = INPUT_KEYBOARD; ip.ki.wScan = 0; ip.ki.time = 0; ip.ki.dwExtraInfo = 0; while (TRUE) { // 等待SLEEP_TIME,期间收到退出信号会立即返回 DWORD waitResult = WaitForSingleObject(hExitEvent, SLEEP_TIME); if (waitResult == WAIT_OBJECT_0) { // 收到退出信号,终止线程 printf("Volume thread exiting...\n"); break; } else if (waitResult == WAIT_TIMEOUT) { // 时间到,执行音量切换操作 times_pressed++; printf("Pressing volume up/down for the %u time!\n", times_pressed); // 按下音量+ ip.ki.wVk = VK_VOLUME_UP; ip.ki.dwFlags = 0; SendInput(1, &ip, sizeof(INPUT)); // 释放音量+ ip.ki.dwFlags = KEYEVENTF_KEYUP; SendInput(1, &ip, sizeof(INPUT)); Sleep(250); // 按下音量- ip.ki.wVk = VK_VOLUME_DOWN; ip.ki.dwFlags = 0; SendInput(1, &ip, sizeof(INPUT)); // 释放音量- ip.ki.dwFlags = KEYEVENTF_KEYUP; SendInput(1, &ip, sizeof(INPUT)); } } return 0; } int main() { // 创建手动重置的退出事件,初始为未触发状态 hExitEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (hExitEvent == NULL) { printf("CreateEvent failed! Error: %d\n", GetLastError()); return 1; } HANDLE volume_h_thread = CreateThread(NULL, 0, volume_loop, NULL, 0, NULL); if (volume_h_thread == NULL) { printf("CreateThread failed! Error: %d\n", GetLastError()); CloseHandle(hExitEvent); return 1; } while (TRUE) { Sleep(10000); // 每10秒切换一次状态 if (g_threadRunning) { puts("Turning thread off!"); // 触发退出事件,通知子线程终止 SetEvent(hExitEvent); // 等待子线程完全退出 WaitForSingleObject(volume_h_thread, INFINITE); // 关闭线程句柄 CloseHandle(volume_h_thread); g_threadRunning = FALSE; // 重置事件,为下次启动做准备 ResetEvent(hExitEvent); } else { puts("Turning thread on!"); // 创建新的子线程 volume_h_thread = CreateThread(NULL, 0, volume_loop, NULL, 0, NULL); if (volume_h_thread == NULL) { printf("CreateThread failed! Error: %d\n", GetLastError()); CloseHandle(hExitEvent); return 1; } g_threadRunning = TRUE; } } // 清理资源(实际不会执行到这里,因为是死循环) SetEvent(hExitEvent); WaitForSingleObject(volume_h_thread, INFINITE); CloseHandle(volume_h_thread); CloseHandle(hExitEvent); return 0; }
关键修改说明
- 事件对象替代全局标志:用
CreateEvent创建手动重置事件,主线程通过SetEvent触发退出信号,子线程用WaitForSingleObject等待,兼顾定时与即时响应终止命令的需求 - 优雅终止线程:子线程收到退出信号后自行退出,避免强制终止线程带来的资源泄漏问题
- 等待线程退出:主线程在终止线程后调用
WaitForSingleObject确保子线程完全退出,再关闭句柄,避免资源泄漏 - 重置事件:每次启动新线程前重置事件,保证新线程能正常等待定时信号
内容的提问来源于stack exchange,提问作者Coldchain9
相关产品推荐
相关产品推荐

