IOCP完成端口模拟线程池

本文详细介绍了一种基于IO完成端口(IOCP)的线程池模拟方案,通过生产者-消费者模式实现多线程间的高效通信。文章展示了如何创建IOCP、消费者线程及生产者线程,并解析了关键函数PostQueuedCompletionStatus和GetQueuedCompletionStatus的使用,以确保线程间的正确同步。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

IOCP完成端口模拟线程池

一,样例介绍

     生产者-消费者模式是一种非常常见的设计模式,它可以很好地模拟实际编程中的大部分使用场景,而IO完成端口也是用来实现多线程之间的通信,因此,本实例基于该模式完成。
     首先,我们需要创建IO完成端口,最后一个参数为0,默认创建的IO完成端口数目就是处理器数目,同时,和要创建一定数目的消费者线程,来处理数据。

//创建1个IO完成端口(最后一个参数为0表示创建处理器个个数的IO完成端口)
	g_hIoCompletionPort = CreateIoCompletionPort(INVALID_HANDLE_VALUE, nullptr, 0, 0);

	//创建的消费者线程(与IO端口绑定的线程)
	SYSTEM_INFO si; 
	GetSystemInfo(&si); 
	int nCount = si.dwNumberOfProcessors * 2;

	for (int i = 0; i < nCount; i++)
	{
		HANDLE hThread = CreateThread(nullptr, 0, ConsumeThread, 0, 0, 0);
		CloseHandle(hThread);
	}

     然后创建一个生产者线程,用来生产数据,同时当IO请求完成后,将已完成的IO通知追加到IO完成端口的队列中。

//生产者线程,产生数据
	HANDLE hThread2 = CreateThread(nullptr, 0, ProductThread, 0, 0, 0);
	CloseHandle(hThread2);

     ConsumeThread实现如下:

//消费者线程
DWORD _stdcall ConsumeThread(LPVOID param)
{
	DWORD dwData;
	DWORD  dwCmpKey = 0;
	OVERLAPPED *pOverlapped = NULL;
	SOverLapped *pOverlappedBuf = nullptr;
	pInfomation pInfo = nullptr;
	while (true)
	{
		if (GetQueuedCompletionStatus(g_hIoCompletionPort, &dwData, &dwCmpKey, &pOverlapped, INFINITE))
		{
			if (dwCmpKey && pOverlapped)
			{
				pOverlappedBuf = CONTAINING_RECORD(pOverlapped, SOverLapped, m_ol);
				pInfo = pOverlappedBuf->pInfo;	//取到我们自定义的数据结构字段

				std::cout << pInfo->szBuf;

				delete pInfo;
				delete pOverlappedBuf;
			}
		}
	}

	return 0;
}

     在这里,我们声明了一个SOverLapped结构体,它里面包含了OVERLAPPED字段,以及一个自定义的消息结构体:

struct SOverLapped
{
	OVERLAPPED m_ol;
	pInfomation pInfo;
};

     CONTAINING_RECORD宏的作用就是根据结构体类型和结构体中成员变量地址和名称则可求出该变量所在结构体的指针。由此得到我们自定义消息指针。
     ProductThread实现如下:

//生产者线程
DWORD _stdcall ProductThread(LPVOID param)
{

	for (int i = 0; i < 100; i++)
	{
		SOverLapped *pBuf = new SOverLapped;

		pInfomation pInfo = new Infomation;
		pInfo->nLength = i;
		sprintf_s(pInfo->szBuf, "hello IoCompletionPort--%d \n", i);

		pBuf->pInfo = pInfo;

		DWORD dwCmKey = 0;
		PostQueuedCompletionStatus(g_hIoCompletionPort, 0, (ULONG)&dwCmKey, &(pBuf->m_ol));
	}

	return 0;
}

     PostQueuedCompletionStatus函数为我们提供了一种方式来与线程池中的所有线程进行通信。当我们终止服务应用程序时,如果各线程和在等待完成端口但是又没有已经完成的IO请求,那么它们将无法被唤醒。此时我们可以通过为线程池中的每个线程都调用一次PostQueuedCompletionStatus,将它们全部唤醒,然后各线程会对GetQueuedCompletionStatus的返回值进行检查,如果发现应用程序正在终止,那么它就可以进行清理工作并正常退出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Simple Simple

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值