多线程临界区使用疑问:CRITICAL_SECTION无法实现连续打印无干扰
解决临界区实现多线程连续打印的问题
嘿,我来帮你梳理下临界区使用时容易踩的坑,你要实现每个线程连续打印5个数字不被干扰的需求,核心问题大概率是临界区的包裹范围或者作用域没处理对。我先给你拆解常见的错误原因,再给你正确的实现示例:
常见错误点分析
- 临界区包裹范围错误:很多人会把
EnterCriticalSection和LeaveCriticalSection放在单个打印语句的前后,这样每个数字打印完就释放临界区,其他线程立刻就能插进来,自然没法连续打印5个数字。正确的做法是把整个5次打印的循环都放在临界区的保护范围内。 - 临界区对象作用域错误:如果每个线程自己定义一个
CRITICAL_SECTION结构体,那各个线程的临界区是独立的,完全起不到互斥作用。必须保证所有线程共享同一个临界区实例。 - 初始化/销毁时机错误:如果在线程创建后才初始化临界区,或者线程还在运行就销毁了临界区,都会导致临界区无法正常工作。必须在创建线程前完成初始化,所有线程执行完毕后再销毁。
正确实现示例代码
#include <windows.h> #include <stdio.h> // 全局临界区对象,确保所有线程都能访问到同一个实例 CRITICAL_SECTION g_printCs; DWORD WINAPI PrintThreadProc(LPVOID lpParam) { int threadNum = *(int*)lpParam; // 进入临界区:整个连续打印的逻辑都被保护 EnterCriticalSection(&g_printCs); printf("=== 线程%d开始连续打印 ===\n", threadNum); for (int i = 0; i < 5; i++) { printf("线程%d: 数字%d\n", threadNum, i + 1); // 模拟耗时操作,让线程切换的效果更明显 Sleep(150); } printf("=== 线程%d打印结束 ===\n", threadNum); // 离开临界区:释放锁,让其他线程可以进入 LeaveCriticalSection(&g_printCs); return 0; } int main() { // 初始化临界区 InitializeCriticalSection(&g_printCs); HANDLE threadHandles[3]; int threadNums[3] = {1, 2, 3}; // 创建3个测试线程 for (int i = 0; i < 3; i++) { threadHandles[i] = CreateThread( NULL, // 默认安全属性 0, // 默认栈大小 PrintThreadProc,// 线程函数 &threadNums[i], // 传递给线程的参数 0, // 立即运行线程 NULL // 不获取线程ID ); } // 等待所有线程执行完毕 WaitForMultipleObjects(3, threadHandles, TRUE, INFINITE); // 销毁临界区 DeleteCriticalSection(&g_printCs); // 关闭线程句柄释放资源 for (int i = 0; i < 3; i++) { CloseHandle(threadHandles[i]); } return 0; }
代码关键点说明
- 共享临界区对象:
g_printCs是全局变量,所有线程都使用这个实例,确保互斥逻辑生效。 - 正确的临界区范围:
EnterCriticalSection在循环前调用,LeaveCriticalSection在循环结束后调用,保证整个连续打印的过程不会被其他线程打断。 - 正确的生命周期:主线程先初始化临界区,再创建线程;等所有线程都执行完毕后,才销毁临界区,避免线程运行时临界区失效。
另外还要注意:如果线程执行过程中可能抛出异常(比如C的异常),要确保LeaveCriticalSection一定会被调用,否则会导致死锁。可以用RAII封装临界区(比如C里写个类,构造时Enter,析构时Leave),避免手动管理的失误。
内容的提问来源于stack exchange,提问作者ezviagintcev
相关产品推荐
相关产品推荐

