Windows C++ 原生线程池同步控制与文件IO操作指南
基于Windows API构建的C++线程池通过任务队列与工作线程分离,实现高并发请求处理。文章重点讲解CreateThreadpoolWork结合互斥锁、信号量、内核事件和临界区的同步用法,并展示异步文件读写、大小获取及指针控制的标准流程。
一、 线程池核心概念与场景
线程池主要由两部分构成:负责存放主线程提交任务的“任务队列”,以及循环从队列中提取并执行任务的“工作线程队列”。这种模型类似于一个生产者(主线程)和多个消费者(工作线程)的结构。在高并发的网络服务端开发中,通常采用“One Loop Per Thread + Thread Pool”模式,由专用线程接收请求并解析,将实际的数据计算任务分发至计算线程池,从而提升资源利用率。
二、 C++原生线程池同步策略
在使用 CreateThreadpoolWork 创建工作单元时,回调函数支持多种系统级同步对象。以下分别演示四种常见的同步方式及其操作入口。
第1步:使用互斥量 (Mutex) 进行同步
目的:确保同一时刻只有一个线程访问共享资源。
入口:调用 CreateMutex 创建对象,传入回调函数。
动作:在线程开始前使用 WaitForSingleObject 锁定,结束后使用 ReleaseMutexWhenCallbackReturns 解锁。
void NTAPI TaskHandlerMutex(PTP_CALLBACK_INSTANCE Instance, PVOID Context, PTP_WORK Work)
{
// 锁定资源
WaitForSingleObject(*(HANDLE *)Context, INFINITE);
for (int x = 0; x < 100; x++)
{
printf("线程ID: %d ---> 子线程: %d \n", GetCurrentThreadId(), x);
}
// 解锁资源
ReleaseMutexWhenCallbackReturns(Instance, *(HANDLE*)Context);
}
void TestMutex()
{
HANDLE hMutex = CreateMutex(NULL, FALSE, NULL);
PTP_WORK pool = CreateThreadpoolWork((PTP_WORK_CALLBACK)TaskHandlerMutex, &hMutex, NULL);
for (int i = 0; i < 1000; i++) SubmitThreadpoolWork(pool);
WaitForThreadpoolWorkCallbacks(pool, FALSE);
CloseHandle(hMutex);
}
第2步:使用内核事件 (Kernel Event) 进行同步
目的:通过信号通知机制控制线程执行。
入口:调用 CreateEvent 创建对象。
动作:等待信号后执行任务,完成后调用 SetEventWhenCallbackReturns 触发信号。
void NTAPI TaskHandlerKern(PTP_CALLBACK_INSTANCE Instance, PVOID Context, PTP_WORK Work)
{
WaitForSingleObject(*(HANDLE *)Context, INFINITE); // 等待事件被置为有信号状态
// ... 执行任务 ...
SetEventWhenCallbackReturns(Instance, *(HANDLE*)Context); // 结束前触发事件
}
void TestKern()
{
HANDLE hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
SetEvent(hEvent); // 预设为有信号状态
PTP_WORK pwk = CreateThreadpoolWork((PTP_WORK_CALLBACK)TaskHandlerKern, &hEvent, NULL);
for (int i = 0; i < 1000; i++) SubmitThreadpoolWork(pwk);
WaitForThreadpoolWorkCallbacks(pwk, FALSE);
CloseHandle(hEvent);
}
第3步:使用信号量 (Semaphore) 进行同步
目的:限制同时执行任务的线程数量或计数。
入口:调用 CreateSemaphore,注意初始值与最大值的设置。
动作:使用 WaitForSingleObject 等待配额,使用 ReleaseSemaphoreWhenCallbackReturns 归还配额。
void NTAPI TaskHandlerSemaphore(PTP_CALLBACK_INSTANCE Instance, PVOID Context, PTP_WORK Work)
{
WaitForSingleObject(*(HANDLE *)Context, INFINITE);
// ... 执行任务 ...
ReleaseSemaphoreWhenCallbackReturns(Instance, *(HANDLE*)Context, 1); // 释放1个计数
}
void TestSemaphore()
{
HANDLE hSemaphore = CreateSemaphore(NULL, 0, 100, NULL);
ReleaseSemaphore(hSemaphore, 10, NULL); // 预先增加10个可用数
PTP_WORK pwk = CreateThreadpoolWork((PTP_WORK_CALLBACK)TaskHandlerSemaphore, &hSemaphore, NULL);
for (int i = 0; i < 1000; i++) SubmitThreadpoolWork(pwk);
WaitForThreadpoolWorkCallbacks(pwk, FALSE);
CloseHandle(hSemaphore);
}
第4步:使用临界区 (Critical Section) 进行同步
目的:轻量级的用户态代码段保护。
入口:初始化 CRITICAL_SECTION。
动作:进入时使用 EnterCriticalSection,离开时使用 LeaveCriticalSectionWhenCallbackReturns。
void NTAPI TaskHandlerLeave(PTP_CALLBACK_INSTANCE Instance, PVOID Context, PTP_WORK Work)
{
EnterCriticalSection((CRITICAL_SECTION*)Context);
// ... 执行任务 ...
LeaveCriticalSectionWhenCallbackReturns(Instance, (CRITICAL_SECTION*)Context);
}
void TestLeave()
{
CRITICAL_SECTION cs;
InitializeCriticalSection(&cs);
PTP_WORK pwk = CreateThreadpoolWork((PTP_WORK_CALLBACK)TaskHandlerLeave, &cs, NULL);
for (int i = 0; i < 1000; i++) SubmitThreadpoolWork(pwk);
WaitForThreadpoolWorkCallbacks(pwk, FALSE);
DeleteCriticalSection(&cs);
}
三、 Windows 基础文件 IO 操作
C++ 可以使用 CreateFile 等 Win32 API 直接处理文件的写入、读取及属性管理。以下演示异步模式的典型用法。
第1步:异步文本读写流程
参数:GENERIC_WRITE 用于写,GENERIC_READ 用于读;FILE_FLAG_SEQUENTIAL_SCAN 优化顺序访问。
动作:先创建句柄,使用 WriteFile 写入数据并 FlushFileBuffers 刷新缓冲区,随后关闭写句柄再打开读句柄进行读取。
int ReadWriteIO()
{
char enContent[] = "hello lyshark";
char deContent[255] = { 0 };
HANDLE hFileWrite = CreateFile(L"d://test.txt", GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (INVALID_HANDLE_VALUE == hFileWrite) return 0;
WriteFile(hFileWrite, enContent, strlen(enContent), NULL, NULL);
FlushFileBuffers(hFileWrite);
CancelSynchronousIo(hFileWrite); // 可选:取消同步IO操作
CloseHandle(hFileWrite);
HANDLE hFileRead = CreateFile(L"d://test.txt", GENERIC_READ, 0, NULL, OPEN_ALWAYS, NULL, NULL);
ReadFile(hFileRead, deContent, 255, NULL, NULL);
std::cout << "读出内容: " << deContent << std::endl;
CloseHandle(hFileRead);
return 1;
}
第2步:获取文件大小
工具:GetFileSizeEx 获取大文件尺寸,返回值为 LARGE_INTEGER 结构。
操作:打开文件后调用 API,将结果打印输出。
int GetFileSize()
{
HANDLE hFile = CreateFile(L"d://test.txt", 0, 0, NULL, OPEN_EXISTING, NULL, NULL);
ULARGE_INTEGER ulFileSize;
GetFileSize(hFile, &ulFileSize.HighPart);
LARGE_INTEGER lFileSize;
GetFileSizeEx(hFile, &lFileSize);
std::cout << "文件大小A: " << ulFileSize.QuadPart << " bytes" << std::endl;
CloseHandle(hFile);
return 1;
}
第3步:移动文件指针与设置
入口:使用 LARGE_INTEGER 指定偏移量。
动作:调用 SetFilePointerEx 设置绝对位置(如从文件头开始),或使用 SetEndOfFile 截断/扩展文件末尾,最后读取指定区域。
int SetFilePointer()
{
DWORD readCount = 0;
char deContent[255] = { 0 };
HANDLE hFile = CreateFile(L"d://test.txt", GENERIC_WRITE, 0, NULL, OPEN_ALWAYS, NULL, NULL);
LARGE_INTEGER liMove;
liMove.QuadPart = 2; // 从第2字节开始
SetFilePointerEx(hFile, liMove, NULL, FILE_BEGIN);
SetEndOfFile(hFile);
ReadFile(hFile, deContent, 255, &readCount, NULL);
std::cout << "移动指针后读取: " << deContent << " 长度: " << readCount << std::endl;
CloseHandle(hFile);
return 0;
}
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













