使用iocp实现简易的线程池

1:定义线程池接口

thread_pool.h

//线程任务回调
typedef void(*thread_jb_cb)(uint64_t job_id, void* udata);

class thread_pool
{
public:
	//开启线程池,最大是16,最小是1
	virtual bool start(uint8_t thread_count) = 0;
	//停止
	virtual void stop() = 0;
	//添加任务,udata:自定义数据,callback:回调,thread_index:线程序号
	virtual uint64_t add_job(void* udata, thread_jb_cb callback, int8_t thread_index = -1) = 0;
};

2:实现线程锁功能

autolock.h

#pragma once
#include <winsock2.h>
#include <windows.h>

class CCriticalSection
{
public:
	void Lock()
	{
		EnterCriticalSection(&m_lock);
	}
	void UnLock()
	{
		LeaveCriticalSection(&m_lock);
	}

	CCriticalSection()
	{
		InitializeCriticalSection(&m_lock);
	}
	~CCriticalSection()
	{
		DeleteCriticalSection(&m_lock);
	}

private:
	CRITICAL_SECTION m_lock;
};


class CAutoLock
{
	CCriticalSection &m_cs;
	CAutoLock();
	const CAutoLock& operator= (const CAutoLock&);
public:
	explicit CAutoLock(CCriticalSection &lock) : m_cs(lock)
	{
		lock.Lock();
	}
	~CAutoLock()
	{
		m_cs.UnLock();
	}
};

3:线程池的实现

3.1:thread_pool_impl.h

#pragma once
#include "thread_pool.h"
#include "autolock.h"

struct iocp_overlapped :public OVERLAPPED
{
	int type;
	void* udata;
	thread_jb_cb callback;
	uint64_t job_id;

	iocp_overlapped(){
		memset(this, 0, sizeof(*this));
	}
};

class thread_pool_impl : public thread_pool{

public:
	thread_pool_impl();
	~thread_pool_impl();

	enum JobType
	{
		Stop,		//没有处理,也就是关闭
		DealMsg,	//处理消息
	};

public:
	//开启线程池,最大是16,最小是1
	virtual bool start(uint8_t thread_count);
	//停止
	virtual void stop();
	//添加任务,
	virtual uint64_t add_job(void* udata, thread_jb_cb callback, int8_t thread_index = -1);

public:
	//处理线程
	void deal_thread(int index);

private:
	uint64_t post_msg_to_iocp(int type, void* udata, thread_jb_cb callback, int8_t thread_index = -1);
	uint64_t get_new_job_id();
	uint8_t get_new_thread_index();

private:
	uint64_t m_job_id;						//jobid
	CCriticalSection m_mutex;				//锁
	uint8_t m_thread_count;					//线程个数
	HANDLE m_iocp_list[MAX_THREAD_COUNT];	//iocp列表
	uint32_t m_thread_id[MAX_THREAD_COUNT];	//线程id
	uint8_t m_thread_index;					//当前的线程序号
	DWORD m_run_thread_count;				//当前运行的线程数量
};

3.2:thread_pool_impl.cpp

#pragma once
#include "thread_pool_impl.h"
#include <process.h>

static thread_pool* s_thread_pool = nullptr;
static thread_pool* get_thread_pool()
{
	if (!s_thread_pool){
		s_thread_pool = new thread_pool_impl();
	}
	return s_thread_pool;
}

static thread_pool* create_thread_pool(){
	return new thread_pool_impl();
}

static void destory_thread_pool(thread_pool* data){
	delete data;
}

struct thread_pool_unit
{
	thread_pool_impl* pool;
	int index;
};

thread_pool_impl::thread_pool_impl()
: m_job_id(0)
, m_thread_index(0)
, m_run_thread_count(0)
, m_thread_count(0)
{
	memset(m_iocp_list, -1, sizeof(m_iocp_list));
}

thread_pool_impl::~thread_pool_impl()
{

}

unsigned __stdcall iocp_thread(void *p){
	thread_pool_unit* unit = (thread_pool_unit*)p;
	unit->pool->deal_thread(unit->index);
	delete unit;
	return 0;
}

bool thread_pool_impl::start(uint8_t thread_count)
{
	if (m_run_thread_count != 0){	//当前有线程在运行
		return false;
	}

	if (thread_count < 1)
		thread_count = 1;
	else if (thread_count > MAX_THREAD_COUNT)
		thread_count = MAX_THREAD_COUNT;
	m_thread_count = thread_count;

	for (int i = 0; i < m_thread_count; ++i)
	{
		m_iocp_list[i] = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, NULL, 1);
	}

	for (int i = 0; i < m_thread_count; ++i)
	{
		thread_pool_unit* unit = new thread_pool_unit();
		unit->pool = this;
		unit->index = i;
		_beginthreadex(NULL, 0, iocp_thread, unit, NULL, &m_thread_id[i]);
	}

	return true;
}

void thread_pool_impl::stop()
{
	for (int i = 0; i < m_thread_count; ++i){
		post_msg_to_iocp(JobType::Stop, nullptr, nullptr, i);
	}
}

uint64_t thread_pool_impl::add_job(void* udata, thread_jb_cb callback, int8_t thread_index /*= -1*/)
{
	return post_msg_to_iocp(JobType::DealMsg, udata, callback, thread_index);;
}

void thread_pool_impl::deal_thread(int index)
{
	CoInitialize(NULL);

	InterlockedIncrement(&m_run_thread_count);

	DWORD nIOBytes = 0;
	ULONG_PTR pKey;
	iocp_overlapped* pOverlap = nullptr;

	while (true)
	{
		BOOL ret = ::GetQueuedCompletionStatus(m_iocp_list[index], &nIOBytes, &pKey, (LPOVERLAPPED*)&pOverlap, INFINITE);
		if (!pOverlap || !ret){
			break;
		}

		if (pOverlap->type <= 0){	//关闭消息
			delete pOverlap;
			pOverlap = nullptr;
			break;
		}

		if (pOverlap->callback){
			pOverlap->callback(pOverlap->job_id, pOverlap->udata);
		}

		delete pOverlap;
		pOverlap = nullptr;
	}

	InterlockedDecrement(&m_run_thread_count);
}

uint64_t thread_pool_impl::post_msg_to_iocp(int type, void* udata, thread_jb_cb callback, int8_t thread_index /*= -1*/)
{
	if (m_thread_count <= 0 || m_run_thread_count <= 0){//线程数量或者正在运行的线程数量都小于0,则关闭
		return 0;
	}

	if (thread_index < 0){
		thread_index = get_new_thread_index();
	}
	if (thread_index >= m_thread_count){
		thread_index = 0;
	}

	uint64_t new_job_id = get_new_job_id();

	iocp_overlapped* overlap = new iocp_overlapped();
	overlap->type = type;
	overlap->udata = udata;
	overlap->callback = callback;
	overlap->job_id = new_job_id;
	PostQueuedCompletionStatus(m_iocp_list[thread_index], 0, (ULONG_PTR)overlap, overlap);

	return new_job_id;
}

uint64_t thread_pool_impl::get_new_job_id()
{
	CAutoLock lock(m_mutex);
	++m_job_id;
	return m_job_id;
}

uint8_t thread_pool_impl::get_new_thread_index()
{
	CAutoLock lock(m_mutex);
	++m_thread_index;
	return m_thread_index;
}

4:线程池的使用

	//创建线程池
	thread_pool* m_thread_pool = new thread_pool_impl();

	//开启
	m_thread_pool->start(16);
	
	//添加任务
	int udata = 1001;
	m_thread_pool->add_job(&udata, [](uint64_t job_id, void* udata){
		int num = *((int*)udata);
		printf("job_id:%lld,num:%d", job_id, num);
	});
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
完成端口I/O模型是一种高效的异步 I/O 模型,其工作原理如下: 1. 程序先创建一个完成端口对象,然后将需要进行异步 I/O 操作的文件句柄或套接字与完成端口对象关联起来。 2. 当异步 I/O 操作完成时,操作系统会将完成信息放入完成端口对象的队列中。 3. 程序可以通过调用 GetQueuedCompletionStatus 函数来获取完成信息。该函数会阻塞等待直到有完成信息到达,或者设置超时时间。 4. 获取到完成信息后,程序可以处理完成的操作,并重新发起新的异步 I/O 操作。 完成端口模型的异步完成通知机制是由操作系统内核实现的。当异步 I/O 操作完成时,操作系统会将完成信息放入完成端口对象的队列中,并唤醒等待在 GetQueuedCompletionStatus 函数上的线程。程序可以通过调用 GetQueuedCompletionStatus 函数获取完成信息。 IOCP 内核对象维护以下 5 个队列: 1. 空闲线程队列:存放空闲的线程对象。 2. 活动线程队列:存放正在执行异步 I/O 操作的线程对象。 3. 完成队列:存放完成的 I/O 操作的信息。 4. 关闭队列:存放需要关闭的文件句柄或套接字。 5. 绑定队列:存放需要进行绑定操作的文件句柄或套接字。 完成队列中存放完成的 I/O 操作的信息,包括完成的操作类型、操作结果、完成的数据大小等信息。 IOCP 通过维护线程池来提高异步 I/O 操作的效率。程序可以通过调用 CreateThread 或者 ThreadPoolCreate 函数来创建线程池。线程数量上限应该根据系统硬件性能和程序的实际需要来设置,一般情况下,线程数量应该小于 CPU 核心数的两倍。 使用该 I/O 模型设计程序的步骤如下: 1. 创建完成端口对象。 2. 创建线程池,将空闲线程对象加入空闲线程队列。 3. 将需要进行异步 I/O 操作的文件句柄或套接字与完成端口对象关联起来。 4. 发起异步 I/O 操作。 5. 等待完成信息到达,获取完成信息。 6. 处理完成信息,重新发起新的异步 I/O 操作。 7. 当需要关闭文件句柄或套接字时,将其放入关闭队列。 8. 当需要绑定文件句柄或套接字时,将其放入绑定队列。 9. 程序结束时,释放资源。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值