C++Socket编程—线程池技术
1.什么是线程池?
线程池(thread pool):是一种多线程的处理形式,处理过程种将任务添加到队列,然后再创建线程后自动启动这些任务。线程池在系统启动时即创建大量空闲的线程,程序将一个任务传给线程池,线程池就会启动一条线程来执行这个任务,执行结束以后,该线程并不会死亡,而是再次返回线程池中成为空闲状态,等待执行下一个任务。
2.为什么要使用线程池?
客户端服务器通信过程中产生卡顿的原因:
• 1.线程的切换 *
• 2.内存的申请和释放 **
• 3.线程的创建和销毁 ***
多线程运行过程中,由于线程频繁创建和销毁带来的效率的损失,会过度销毁系统资源,以及过度切换线程的危险,从而导致可能系统资源崩溃。我们可使用线程池技术来避免。使用线程池技术可以更好地来提高性能。
3.线程池工作机制:
线程池编程模式下,任务是提交给整个线程池,而不是提交给某个线程,线程池拿到任务后就在内部寻找空闲的线程并将任务交给某个空闲的线程,一个线程只能执行一个任务,但可以同时向线程池提交多个任务。
4.如何设计一个线程池?
3.1 所有的线程都等待信号, 当有个请求来的时候, 就释放一个信号, 拿到信号的线程干活, 干完活之后信号数减一。
3.2使用回调, 不同的请求封装成不同的函数, 当对应请求来的时候, 将函数地址丢给线程运行。
3.3准备一个请求队列, 当有请求来的时候, 将请求放到队列,同时释放一个信号. 拿到信号的线程会从队列里面取出请求并处理. 处理完之后, 信号减一。
5.池技术在何时使用?
当资源申请和释放比资源使用的效率带来的损失大的时候使用
6.代码示例:创建并使用一个简单的线程池:
MyThreadPool.h:
#pragma once
#include<windows.h>
#include<queue>
using namespace std;
//任务接口
class IThreadPoolTask
{
public:
virtual ~IThreadPoolTask() {};
virtual void RunTask() = 0;
};
//线程池
class MyThreadPool
{
public:
MyThreadPool();
~MyThreadPool();
BOOL CreateThreadPool(DWORD dwThreadCount);
VOID DestroyThread();
void PostTask(IThreadPoolTask* pTask);
private:
static DWORD WINAPI TaskThread(LPVOID pParam);
private:
HANDLE m_hSemphore;//信号量,用于通知线程池中的线程,有新的请求来了
queue<IThreadPoolTask*> m_queueTasks;//任务队列
DWORD m_dwTreadCount; //线程个数
CRITICAL_SECTION m_cs;//用于队列的同步
};
MyThreadPool.cpp:
#include "MyThreadPool.h"
MyThreadPool::MyThreadPool()
{
InitializeCriticalSection(&m_cs);
}
MyThreadPool::~MyThreadPool()
{
DeleteCriticalSection(&m_cs);
}
BOOL MyThreadPool::CreateThreadPool(DWORD dwThreadCount)
{
m_hSemphore = CreateSemaphore(
NULL,
0,//没有任务,则释放出的信号为0
MAXLONG,//取最大任务个数
NULL
);
if (m_hSemphore == NULL)
{
return FALSE;
}
//创建线程
m_dwTreadCount = dwThreadCount;
for (DWORD i = 0; i < m_dwTreadCount; ++i)
{
HANDLE hThread = CreateThread(NULL, 0, TaskThread, this, 0, NULL);
CloseHandle(hThread);
}
}
void MyThreadPool::DestroyThread()
{
CloseHandle(m_hSemphore);
}
void MyThreadPool::PostTask(IThreadPoolTask* pTask)
{
EnterCriticalSection(&m_cs);
//向队列种添加任务同时添加一下信号
m_queueTasks.push(pTask);
ReleaseSemaphore(m_hSemphore, 1, NULL);
//
if (m_queueTasks.size() > 2)
{
HANDLE hThread = CreateThread(NULL, 0, TaskThread, this, 0, NULL);
CloseHandle(hThread);
}
LeaveCriticalSection(&m_cs);
}
DWORD WINAPI MyThreadPool::TaskThread(LPVOID pParam)
{
MyThreadPool* pThis = (MyThreadPool*)pParam;
//从队列种拿出任务,执行任务
while (TRUE)
{
DWORD dwRet = WaitForSingleObject(pThis->m_hSemphore, INFINITE);
//线程池被销毁
if (dwRet == WAIT_FAILED)
{
return 0;
}
//从队列种取出任务
EnterCriticalSection(&pThis->m_cs);
IThreadPoolTask* pTask = pThis->m_queueTasks.front();
pThis->m_queueTasks.pop();
LeaveCriticalSection(&pThis->m_cs);
//执行任务
pTask->RunTask();
delete pTask;
}
return 0;
}
测试:使用线程池创建线程:
#include <iostream> #include"MyThreadPool.h" class CMyTask :public IThreadPoolTask { public: virtual void RunTask() override { printf("tid: %d \tidx:%d \r\n", GetCurrentThreadId(), m_nIdx); } CMyTask(int nIdx): m_nIdx(nIdx) {} ~CMyTask() {} private: int m_nIdx = 0; }; int main() { MyThreadPool tp; tp.CreateThreadPool(4); for (int i = 0; i < 100; ++i) { CMyTask* pTask = new CMyTask(i); tp.PostTask(pTask); } system("pause"); return 0; }
效果: