Windows API一日一练(60)CreateIoCompletionPort和GetQueuedCompletionStatus函数

Windows系统里,使用完成端口是高性能的方法之一,比如把完成端口使用到线程池和网络服务器里。现在就通过线程池的方法来介绍怎么样使用完成端口,高性能的服务器以后再仔细地介绍怎么样构造它。其实完成端口是一个队列,所有的线程都在等消息出现,如果队列里有消息,就每个线程去获取一个消息执行它。先用函数CreateIoCompletionPort来创建一个消息队列,然后使用GetQueuedCompletionStatus函数来从队列获取消息,使用函数PostQueuedCompletionStatus来向队列里发送消息。通过这三个函数就实现完成端口的消息循环处理。
函数CreateIoCompletionPortGetQueuedCompletionStatusPostQueuedCompletionStatus声明如下:
WINBASEAPI
__out
HANDLE
WINAPI
CreateIoCompletionPort(
__in HANDLE FileHandle,
__in_opt HANDLE ExistingCompletionPort,
__in ULONG_PTR CompletionKey,
__in DWORD NumberOfConcurrentThreads
);
WINBASEAPI
BOOL
WINAPI
GetQueuedCompletionStatus(
__inHANDLE CompletionPort,
__out LPDWORD lpNumberOfBytesTransferred,
__out PULONG_PTR lpCompletionKey,
__out LPOVERLAPPED *lpOverlapped,
__inDWORD dwMilliseconds
);
WINBASEAPI
BOOL
WINAPI
PostQueuedCompletionStatus(
__in HANDLE CompletionPort,
__in DWORD dwNumberOfBytesTransferred,
__in ULONG_PTR dwCompletionKey,
__in_opt LPOVERLAPPED lpOverlapped
);
FileHandle是关联的文件句柄。
ExistingCompletionPort是已经存在的完成端口。
CompletionKey是传送给处理函数的参数。
NumberOfConcurrentThreads是有多少个线程在访问这个消息队列。
CompletionPort是已经存在的完成端口。
lpCompletionKey是传送给处理函数的参数。
lpOverlapped是传送给处理函数的参数。
dwMilliseconds是等待时间。
dwNumberOfBytesTransferred是传送了多少个字节。
调用函数的例子如下:
#001#pragma once
#002
#003#include "Thread.h"
#004
#005
#006//使用IOCP实现线程池。
#007//蔡军生2007/10/29 QQ:9073204 深圳
#008class CThreadPools
#009{
#010public:
#011
#012CThreadPools(void)
#013{
#014 m_nThreadCount = 2;
#015 }
#016
#017~CThreadPools(void)
#018{
#019}
#020
#021bool Init(void)
#022{
#023 //创建一个IOCP
#024 m_hQueue = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, m_nThreadCount);
#025 if (m_hQueue == NULL)
#026 {
#027 //创建IOCP失败。
#028 return false;
#029 }
#030}
#031
#032int GetThreadCount(void) const
#033{
#034 return m_nThreadCount;
#035}
#036
#037//线程池处理的内容。
#038DWORD Run(void)
#039{
#040 DWORD dwBytesTransfered;
#041 ULONG_PTR dwCompletionKey;
#042
#043 OVERLAPPED* pOverlapped;
#044
#045 //等一个IOCP的消息。
#046 while (GetQueuedCompletionStatus(m_hQueue, &dwBytesTransfered, &dwCompletionKey, &pOverlapped, INFINITE))
#047 {
#048 if (pOverlapped == ((OVERLAPPED*) ((__int64) -1)) )
#049 {
#050 //退出。
#051 OutputDebugString(_T("退出 /r/n"));
#052 break;
#053 }
#054 else
#055
#056 {
#057 WPARAM request = (WPARAM) dwCompletionKey;
#058
#059 //处理消息。
#060 OutputDebugString(_T("GetQueuedCompletionStatus /r/n"));
#061 }
#062 }
#063
#064 return 0;
#065}
#066
#067//发送处理的消息。
#068bool QueueRequest(WPARAM wParam)
#069{
#070 //IOCP里发送一条消息。
#071 if (!PostQueuedCompletionStatus(m_hQueue, 0, (ULONG_PTR) wParam, NULL))
#072 {
#073 return false;
#074 }
#075
#076 return true;
#077}
#078
#079//关闭所有线程。
#080void Close(void)
#081{
#082 for (int i = 0; i < m_nThreadCount; i++)
#083 {
#084 PostQueuedCompletionStatus(m_hQueue, 0, 0, (OVERLAPPED*) ((__int64) -1) );
#085 }
#086}
#087
#088protected:
#089//接收消息处理的队列。
#090HANDLE m_hQueue;
#091
#092//线程个数。
#093int m_nThreadCount;
#094};
#095
#096//////////////////////////////////////////////////////////////////////////
#097class CThreads :
#098public CThread
#099{
#100public:
#101CThreads(CThreadPools* pPool)
#102{
#103 m_pPool = pPool;
#104}
#105virtual ~CThreads(void)
#106{
#107
#108}
#109
#110
#111protected:
#112//
#113//线程运行函数。
#114//在这里可以使用类里的成员,也可以让派生类实现更强大的功能。
#115//蔡军生 2007/10/29
#116virtual DWORD Run(void)
#117{
#118 //
#119 if (m_pPool)
#120 {
#121 returnm_pPool->Run();
#122 }
#123
#124 return -1;
#125}
#126
#127protected:
#128CThreadPools* m_pPool;
#129
#130};
解决:软件多线程运行时遇到【内存不断升高】甚至爆表! 因为本人是个小白,多线程经常用,但是线程池并没有用过,(一听到线程池,总感觉高大上) 但是近期写彩票软件的时候发现,多线程长期操作会导致内容不断的升高直至报错,遂想起了线程池,完善后发现不是一般的叼 啊!!! 先简单的说下多线程线程池的区别: 1、多线程每次启动的时候系统都要分配一定的资源出来(主要占的就是内存),而不断的启动线程、启动线程、启动线程 循环的启动线程,就造成了系统资源极大的浪费,甚至不释放的情况,继续下去内存就OVER了! 2、线程池则完美的解决了这个问题,线程池的原理就是事先申请好指定数量的线程所使用的资源,而且这些资源是不断的重复利用的!可利用任务管理器看到程序的线程数量的变化(在使用普通的多线程时:线程数会根据软件启动的线程数量增加,循环完了之后线程数量也就减少了,但是内存资源不减少,再启动线程内存继续飙升!  而在使用【线程池】的时候:线程数一直保持线程池中的数量,无论你是否启动多线程进行运算,线程数量都不会变化,同时内存也不会有多大的变化,更不会不断的飙升!) 也许我的表达能力不足,反正大家知道在启用多线程的时候尽量使用线程池可以保证内存不会飙升就行了! 这里说的启动多线程是指循环启动‘同一个子程序’线程:
<think>我们将使用Windows API实现一个线程循环唤醒另一个线程的机制。主要使用以下API: - CreateThread:创建线程 - CreateMutex:创建互斥锁 - WaitForSingleObject:等待对象(如互斥锁)变为有信号状态 - ReleaseMutex:释放互斥锁 - CloseHandle:关闭句柄 方案设计: 1. 创建两个线程:工作线程(被唤醒的线程)控制线程(唤醒工作线程的线程)。 2. 使用一个互斥锁(Mutex)来控制工作线程的等待唤醒。 3. 工作线程在循环中等待互斥锁,当控制线程释放互斥锁时,工作线程被唤醒并执行任务,然后重新进入等待状态。 4. 控制线程负责在需要时释放互斥锁以唤醒工作线程。 注意:初始时,互斥锁由主线程创建并拥有(即处于无信号状态),这样工作线程在启动后就会等待。控制线程通过释放互斥锁来唤醒工作线程。 步骤: a. 主线程创建互斥锁,初始状态为无信号(即主线程拥有锁)。 b. 创建工作线程,工作线程尝试获取互斥锁(等待),因此会阻塞。 c. 创建控制线程,控制线程在需要时释放互斥锁(使其变为有信号状态),从而唤醒工作线程。 d. 工作线程被唤醒后执行任务,然后再次尝试获取互斥锁(即再次等待)。 但是,这里有一个问题:互斥锁被释放后,工作线程获取到锁,然后工作线程必须释放锁才能让控制线程再次获取?但我们的设计是控制线程再次释放锁来唤醒工作线程。所以我们需要改变策略: 另一种方案:使用两个互斥锁或者使用事件(Event)可能更简单。但题目要求用互斥锁,我们可以用两个互斥锁来实现一个交替的唤醒机制。 然而,我们也可以用一个互斥锁实现循环唤醒,但需要工作线程在执行完任务后释放锁,然后控制线程再次获取锁并释放(这样工作线程才能再次获取)?这样控制线程就需要循环获取释放。 但这样控制线程会一直占用CPU,不是高效的方式。因此,我们使用两个互斥锁(AB): - 初始:互斥锁A由主线程创建并拥有(无信号),互斥锁B由主线程创建并释放(有信号)。 - 工作线程: 循环: 等待互斥锁A(初始无信号,所以阻塞) 当互斥锁A被控制线程释放后,工作线程被唤醒,然后获取互斥锁A(此时互斥锁A变为无信号) 执行任务 释放互斥锁B(让控制线程可以再次唤醒) - 控制线程: 循环: 等待互斥锁B(初始有信号,所以立即获取) 做一些操作(比如等待用户输入)来决定何时唤醒工作线程 释放互斥锁A(唤醒工作线程) 然后等待互斥锁B(因为工作线程执行完后会释放互斥锁B,所以控制线程会再次获取互斥锁B,从而进入下一轮) 这样,两个线程通过两个互斥锁交替进行同步。 但是,题目要求一个线程循环唤醒另一个线程,所以控制线程需要多次唤醒工作线程。 我们采用以下步骤: 主线程: 创建互斥锁A(初始无信号,即主线程不释放,所以初始状态为无信号) 创建互斥锁B(初始有信号,即主线程创建后立即释放,所以初始状态为有信号) 工作线程: while(运行标志) { WaitForSingleObject(互斥锁A, INFINITE); // 等待控制线程释放A(变为有信号) // 被唤醒后,互斥锁A变为无信号(因为被工作线程获取) 执行任务... ReleaseMutex(互斥锁B); // 释放互斥锁B,让控制线程可以继续 } 控制线程: while(运行标志) { WaitForSingleObject(互斥锁B, INFINITE); // 等待工作线程释放B(变为有信号) // 这里可以等待用户输入,或者定时等,然后决定唤醒工作线程 做一些操作... ReleaseMutex(互斥锁A); // 释放互斥锁A,唤醒工作线程 } 注意:初始时,互斥锁A是无信号的(由主线程创建时拥有,不释放),互斥锁B是有信号的(主线程创建后立即释放)。控制线程首先运行,获取互斥锁B(因为有信号,所以立即获取),然后释放互斥锁A(唤醒工作线程),然后控制线程在循环中再次等待互斥锁B(此时被工作线程持有,所以等待)。工作线程被唤醒后执行任务,然后释放互斥锁B,控制线程再次获取互斥锁B,然后再次释放互斥锁A...如此循环。 但是,这样控制线程工作线程是交替执行的,每次工作线程执行完任务后,控制线程必须再次释放互斥锁A才能唤醒工作线程。 然而,题目要求是“循环唤醒”,即控制线程可以多次唤醒工作线程,而工作线程每次被唤醒执行任务后继续等待下一次唤醒。 因此,这个方案是可行的。 下面我们用代码实现: 注意:在退出时,需要设置运行标志,并确保两个线程都能退出。 我们使用两个全局变量来作为运行标志,并使用Windows的事件(Event)来通知线程退出,但题目要求互斥锁,所以我们也可以用互斥锁保护一个退出标志。但为了简单,我们使用原子操作(Interlocked系列)或者volatile(在简单场景下)来作为退出标志。 但是,我们这里使用一个事件(Event)来通知退出,因为题目要求用互斥锁实现唤醒,退出机制可以灵活处理。如果严格要求只使用互斥锁,我们可以用另一个互斥锁来保护退出标志并等待,但这样会复杂。为了专注于循环唤醒,我们使用一个事件来通知退出。 不过,为了满足题目要求,我们也可以让控制线程在循环中等待用户输入,当用户输入退出命令时,设置退出标志,然后唤醒工作线程并等待其退出。 具体实现: 步骤: 1. 定义两个互斥锁:g_hMutexA, g_hMutexB。 2. 定义全局退出标志:g_bExit。 3. 主线程初始化互斥锁退出标志。 4. 创建工作线程控制线程。 5. 主线程等待事件或用户输入来退出。 6. 设置退出标志,并唤醒两个线程(通过释放互斥锁的方式),然后等待两个线程结束。 但是,控制线程工作线程的循环条件都是检查退出标志,所以当退出标志为true时,它们会退出循环。 下面我们写代码:</think># 使用Windows API实现线程循环唤醒机制 下面我将使用Windows API实现一个线程循环唤醒另一个线程的机制。这种模式在生产者-消费者、任务调度等场景中非常有用。 ## 完整解决方案 ### 使用互斥锁事件对象实现循环唤醒 ```cpp #include <Windows.h> #include <iostream> #include <string> // 全局同步对象 HANDLE g_hMutex = NULL; // 互斥锁 HANDLE g_hWakeEvent = NULL; // 唤醒事件 HANDLE g_hWorkerThread = NULL; // 工作线程句柄 volatile BOOL g_bRunning = FALSE; // 运行标志 // 工作线程函数 DWORD WINAPI WorkerThread(LPVOID lpParam) { std::cout << "工作线程启动 (ID: " << GetCurrentThreadId() << ")" << std::endl; int taskCount = 0; while (g_bRunning) { // 等待唤醒事件 DWORD dwWaitResult = WaitForSingleObject(g_hWakeEvent, INFINITE); if (!g_bRunning) break; if (dwWaitResult == WAIT_OBJECT_0) { // 获取互斥锁以访问共享资源 WaitForSingleObject(g_hMutex, INFINITE); // 执行任务 taskCount++; std::cout << "工作线程执行任务 #" << taskCount << " (ID: " << GetCurrentThreadId() << ")" << std::endl; // 模拟工作耗时 Sleep(300); // 释放互斥锁 ReleaseMutex(g_hMutex); // 重置事件,准备下一次唤醒 ResetEvent(g_hWakeEvent); } else { std::cerr << "等待事件失败! 错误代码: " << GetLastError() << std::endl; break; } } std::cout << "工作线程退出" << std::endl; return 0; } int main() { // 创建互斥锁 g_hMutex = CreateMutex(NULL, FALSE, NULL); if (g_hMutex == NULL) { std::cerr << "创建互斥锁失败! 错误代码: " << GetLastError() << std::endl; return 1; } // 创建自动重置事件 g_hWakeEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if (g_hWakeEvent == NULL) { std::cerr << "创建事件失败! 错误代码: " << GetLastError() << std::endl; CloseHandle(g_hMutex); return 1; } // 启动工作线程 g_bRunning = TRUE; DWORD dwThreadId; g_hWorkerThread = CreateThread( NULL, // 默认安全属性 0, // 默认堆栈大小 WorkerThread, // 线程函数 NULL, // 无参数 0, // 默认创建标志 &dwThreadId // 接收线程ID ); if (g_hWorkerThread == NULL) { std::cerr << "创建工作线程失败! 错误代码: " << GetLastError() << std::endl; CloseHandle(g_hMutex); CloseHandle(g_hWakeEvent); return 1; } std::cout << "主线程 (ID: " << GetCurrentThreadId() << ")" << std::endl; std::cout << "按回车键唤醒工作线程 (输入 'q' 退出)..." << std::endl; char input = 0; while (input != 'q') { std::cin.get(input); if (input == '\n') { // 唤醒工作线程 if (!SetEvent(g_hWakeEvent)) { std::cerr << "设置事件失败! 错误代码: " << GetLastError() << std::endl; } else { std::cout << "唤醒信号已发送" << std::endl; } } } // 停止工作线程 g_bRunning = FALSE; SetEvent(g_hWakeEvent); // 确保线程能退出 // 等待工作线程结束 WaitForSingleObject(g_hWorkerThread, INFINITE); // 清理资源 CloseHandle(g_hWorkerThread); CloseHandle(g_hWakeEvent); CloseHandle(g_hMutex); std::cout << "程序结束" << std::endl; return 0; } ``` ## 实现原理详解 ### 1. 同步对象设计 ```mermaid graph LR A[主线程] --> B[唤醒事件] B --> C[工作线程] C --> D[互斥锁] D --> E[执行任务] E --> B ``` ### 2. 关键Windows API 1. **CreateMutex** - 创建互斥锁 - 用于保护共享资源 - 确保任务执行的原子性 2. **CreateEvent** - 创建事件对象 - 用于线程间通知 - 自动重置事件:信号后自动恢复无信号状态 3. **SetEvent** - 设置事件为有信号状态 - 主线程调用此函数唤醒工作线程 4. **ResetEvent** - 重置事件为无信号状态 - 工作线程在任务完成后调用 5. **WaitForSingleObject** - 等待对象 - 工作线程等待事件信号 - 获取互斥锁时使用 ### 3. 线程工作流程 ```mermaid sequenceDiagram participant Main as 主线程 participant Event as 事件对象 participant Worker as 工作线程 participant Mutex as 互斥锁 Main->>Event: SetEvent() 设置事件信号 Worker->>Event: WaitForSingleObject() 等待事件 Event-->>Worker: 事件触发 Worker->>Mutex: WaitForSingleObject() 请求互斥锁 Mutex-->>Worker: 授予互斥锁 Worker->>Worker: 执行任务 Worker->>Mutex: ReleaseMutex() 释放互斥锁 Worker->>Event: ResetEvent() 重置事件 Worker->>Event: 返回等待状态 ``` ## 高级实现:带任务数据的循环唤醒 下面扩展实现,允许主线程向工作线程传递数据: ```cpp #include <Windows.h> #include <iostream> #include <queue> #include <string> // 任务数据结构 struct TaskData { int id; std::string message; }; // 全局同步对象 HANDLE g_hMutex = NULL; HANDLE g_hWakeEvent = NULL; HANDLE g_hWorkerThread = NULL; volatile BOOL g_bRunning = FALSE; // 任务队列 std::queue<TaskData> g_taskQueue; // 工作线程函数 DWORD WINAPI WorkerThread(LPVOID lpParam) { std::cout << "工作线程启动 (ID: " << GetCurrentThreadId() << ")" << std::endl; while (g_bRunning) { // 等待唤醒事件 WaitForSingleObject(g_hWakeEvent, INFINITE); if (!g_bRunning) break; // 处理所有待处理任务 while (true) { // 获取互斥锁 WaitForSingleObject(g_hMutex, INFINITE); if (g_taskQueue.empty()) { ReleaseMutex(g_hMutex); break; } // 获取任务 TaskData task = g_taskQueue.front(); g_taskQueue.pop(); // 释放互斥锁(尽早释放) ReleaseMutex(g_hMutex); // 执行任务 std::cout << "工作线程处理任务 #" << task.id << ": " << task.message << " (ID: " << GetCurrentThreadId() << ")" << std::endl; // 模拟工作耗时 Sleep(200); } // 重置事件 ResetEvent(g_hWakeEvent); } std::cout << "工作线程退出" << std::endl; return 0; } int main() { // 创建互斥锁 g_hMutex = CreateMutex(NULL, FALSE, NULL); if (g_hMutex == NULL) { std::cerr << "创建互斥锁失败! 错误代码: " << GetLastError() << std::endl; return 1; } // 创建自动重置事件 g_hWakeEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if (g_hWakeEvent == NULL) { std::cerr << "创建事件失败! 错误代码: " << GetLastError() << std::endl; CloseHandle(g_hMutex); return 1; } // 启动工作线程 g_bRunning = TRUE; DWORD dwThreadId; g_hWorkerThread = CreateThread(NULL, 0, WorkerThread, NULL, 0, &dwThreadId); if (g_hWorkerThread == NULL) { std::cerr << "创建工作线程失败! 错误代码: " << GetLastError() << std::endl; CloseHandle(g_hMutex); CloseHandle(g_hWakeEvent); return 1; } std::cout << "主线程 (ID: " << GetCurrentThreadId() << ")" << std::endl; std::cout << "输入任务消息 (输入 'q' 退出):" << std::endl; int taskId = 1; std::string input; while (true) { std::cout << "> "; std::getline(std::cin, input); if (input == "q") break; // 准备任务数据 TaskData task; task.id = taskId++; task.message = input; // 添加到任务队列 WaitForSingleObject(g_hMutex, INFINITE); g_taskQueue.push(task); ReleaseMutex(g_hMutex); // 唤醒工作线程 if (!SetEvent(g_hWakeEvent)) { std::cerr << "设置事件失败! 错误代码: " << GetLastError() << std::endl; } } // 停止工作线程 g_bRunning = FALSE; SetEvent(g_hWakeEvent); // 等待工作线程结束 WaitForSingleObject(g_hWorkerThread, INFINITE); // 清理资源 CloseHandle(g_hWorkerThread); CloseHandle(g_hWakeEvent); CloseHandle(g_hMutex); std::cout << "程序结束" << std::endl; return 0; } ``` ## 性能优化技巧 ### 1. 使用信号量控制任务数量 ```cpp // 添加全局信号量 HANDLE g_hSemaphore = CreateSemaphore(NULL, 0, MAX_TASKS, NULL); // 主线程添加任务后 ReleaseSemaphore(g_hSemaphore, 1, NULL); // 工作线程中 WaitForSingleObject(g_hSemaphore, INFINITE); ``` ### 2. 多工作线程实现 ```cpp // 创建多个工作线程 const int WORKER_COUNT = 4; HANDLE hWorkers[WORKER_COUNT]; for (int i = 0; i < WORKER_COUNT; i++) { hWorkers[i] = CreateThread(NULL, 0, WorkerThread, NULL, 0, NULL); } // 等待所有线程结束 WaitForMultipleObjects(WORKER_COUNT, hWorkers, TRUE, INFINITE); ``` ### 3. 使用IO完成端口 ```cpp // 创建IO完成端口 HANDLE hCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, 0); // 工作线程 DWORD WINAPI WorkerThread(LPVOID lpParam) { DWORD bytesTransferred; ULONG_PTR completionKey; LPOVERLAPPED overlapped; while (GetQueuedCompletionStatus(hCompletionPort, &bytesTransferred, &completionKey, &overlapped, INFINITE)) { // 处理任务 } return 0; } // 主线程投递任务 PostQueuedCompletionStatus(hCompletionPort, sizeof(TaskData), (ULONG_PTR)&task, NULL); ``` ## 应用场景 1. **GUI应用程序** - 主线程处理用户界面 - 工作线程执行耗时操作 - 使用PostMessage通知UI更新 2. **服务程序** - 主线程监听网络请求 - 工作线程处理请求 - 使用完成端口高效处理 3. **数据处理流水线** - 多级处理管道 - 每级使用独立工作线程 - 级间使用事件或信号量同步 4. **游戏引擎** - 渲染线程 - 物理计算线程 - AI处理线程 - 使用同步对象协调帧更新 ## 编译与运行 ### 编译命令 ```bash # 使用MSVC编译器 cl /EHsc /nologo /O2 thread_wakeup.cpp /link /out:thread_wakeup.exe # 使用MinGW编译器 g++ -O2 -static thread_wakeup.cpp -o thread_wakeup.exe -lstdc++ -lpthread ``` ### 运行示例 ``` 主线程 (ID: 1234) 按回车键唤醒工作线程 (输入 'q' 退出)... [回车] 唤醒信号已发送 工作线程执行任务 #1 (ID: 5678) [回车] 唤醒信号已发送 工作线程执行任务 #2 (ID: 5678) q 工作线程退出 程序结束 ``` ## 错误处理与调试 1. **常见错误代码** - `ERROR_INVALID_HANDLE` - 无效句柄 - `WAIT_TIMEOUT` - 等待超时 - `WAIT_ABANDONED` - 互斥锁被放弃 2. **调试技巧** ```cpp // 检查API返回值 if (!SetEvent(g_hWakeEvent)) { DWORD err = GetLastError(); std::cerr << "SetEvent失败! 错误代码: " << err << std::endl; // 使用FormatMessage获取错误描述 LPVOID lpMsgBuf; FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf, 0, NULL); std::cerr << "错误描述: " << (LPCTSTR)lpMsgBuf << std::endl; LocalFree(lpMsgBuf); } ``` 3. **死锁检测** - 使用`WaitForSingleObject`设置超时 - 记录等待时间过长的情况 - 避免在持有锁时调用可能阻塞的函数 ## 安全注意事项 1. **资源泄漏预防** - 确保所有句柄都被正确关闭 - 使用RAII包装器管理资源 ```cpp class AutoHandle { HANDLE m_handle; public: AutoHandle(HANDLE handle) : m_handle(handle) {} ~AutoHandle() { if (m_handle) CloseHandle(m_handle); } operator HANDLE() const { return m_handle; } }; ``` 2. **线程安全退出** - 使用原子变量作为退出标志 - 确保唤醒所有等待线程 - 等待所有线程结束 3. **异常处理** - 在任务执行周围添加异常处理 - 避免异常导致线程终止 ```cpp __try { // 执行任务 } __except(EXCEPTION_EXECUTE_HANDLER) { std::cerr << "任务执行异常" << std::endl; } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值