大家好,我是 DongGu ,是一名软件工程专业大二的学生,写博客一方面是为了记录自己的学习过程,把自己犯的错误进行分享。但由于水平有限,博客中难免会有一些错误出现,有纰漏之处恳请各位大佬不吝赐教!有任何问题可以评论 或者 ___>
QQ联系(1521839703)
- 本代码还是跟老王学到的, 只不过那个是linux版本,改成c++11可以在win下进行调试,
- 对于一些函数本质原理不太了解,
为什么要用到线程池:
1. 肯定是为了速度,并且提前创建好线程, 避免动态创建线程,提高了稳定性
2. 用类来管理和调度这些线程, 不断循环, 调度,处理, 显著的提高运行效率
#include<vector>
#include<atomic>
#include<mutex>
#include<list>
#include<thread>
#include<iostream>
#include<Windows.h>
#include<algorithm>
#include<condition_variable>
using namespace std;
class CThreadPool {
public:
struct ThreadItem
{
thread mythread;
CThreadPool* _pThis; //记录线程池的指针
bool ifrunning; //标记是否正式启动起来,启动起来后,才允许调用StopAll()来释放
//构造函数
ThreadItem(CThreadPool* pthis) :_pThis(pthis), ifrunning(false) {}
//析构函数
~ThreadItem() {}
};
CThreadPool();
~CThreadPool();
void* ThreadFunc(void* threadData); //新线程的线程回调函数
bool Create(int threadNum); //创建该线程池中的所有线程
void StopAll(); //使线程池中的所有线程退出
void clearMsgRecvQueue(); //清理接收消息队列
void inMsgRecvQueueAndSignal(char* buf); //收到一个完整消息后,入消息队列,并触发线程池中线程来处理该消息
void Call(); //来任务了,调一个线程池中的线程下来干活
int getRecvMsgQueueCount() { return m_iRecvMsgQueueCount; } //获取接收消息队列大小
static bool m_shutdown; //线程退出标志,false不退出,true退出
int m_iThreadNum; //要创建的线程数量
std::atomic<int> m_iRunningThreadNum; //线程数, 运行中的线程数,原子操作
std::vector<ThreadItem*> m_threadVector; //线程 容器,容器里就是各个线程了
//接收消息队列相关
list<char*> m_MsgRecvQueue; //接收数据消息队列
int m_iRecvMsgQueueCount;//收消息队列大小
mutex m_pthreadMutex;
condition_variable m_pthreadCond;
};
bool CThreadPool::m_shutdown = false; //线程退出标志,false不退出,true退出
//构造函数
CThreadPool::CThreadPool()
{
m_iRunningThreadNum = 0; //正在运行的线程,开始给个0【注意这种写法:原子的对象给0也可以直接赋值,当整型变量来用】
m_iRecvMsgQueueCount = 0; //收消息队列
}
//析构函数
CThreadPool::~CThreadPool()
{
//资源释放在StopAll()里统一进行,就不在这里进行了
//接收消息队列中内容释放
clearMsgRecvQueue();
}
void CThreadPool::clearMsgRecvQueue()
{
char* sTmpMempoint;
//尾声阶段,需要互斥?该退的都退出了,该停止的都停止了,应该不需要退出了
while (!m_MsgRecvQueue.empty())
{
sTmpMempoint = m_MsgRecvQueue.front();
cout << "delete -> " << sTmpMempoint << endl;
m_MsgRecvQueue.pop_front();
delete[]sTmpMempoint;
}
}
bool CThreadPool::Create(int threadNum)
{
ThreadItem* pNew;
m_iThreadNum = threadNum; //保存要创建的线程数量
for (int i = 0; i < m_iThreadNum; ++i)
{
m_threadVector.push_back(pNew = new ThreadItem(this)); //创建 一个新线程对象 并入到容器中
pNew->mythread = thread(&CThreadPool::ThreadFunc, this, pNew);
} //end for
std::vector<ThreadItem*>::iterator iter;
lblfor:
for (iter = m_threadVector.begin(); iter != m_threadVector.end(); iter++)
{
cout << (*iter)->mythread.get_id() << "'s ifrunning " << (*iter)->ifrunning << endl;
if ((*iter)->ifrunning == false) //这个条件保证所有线程完全启动起来,以保证整个线程池中的线程正常工作;
{
Sleep(100); //100毫秒
goto lblfor;
}
}
return true;
}
void* CThreadPool::ThreadFunc(void* threadData) //新线程的线程回调函数
{
ThreadItem* pThread = static_cast<ThreadItem*>(threadData);
CThreadPool* pThreadPoolObj = pThread->_pThis;
while (1) {
/*
* 疑问, 是不是每个锁到这里,都是创建一个没有加锁的unique,有待测试,主要condition_variable要unique类型
*/
unique_lock<mutex> lck(m_pthreadMutex);//创建一个没有加锁的myunique_lock
while ((pThreadPoolObj->m_MsgRecvQueue.size() == 0) && m_shutdown == false)
{
if (pThread->ifrunning == false)
{
pThread->ifrunning = true;
cout << pThread->mythread.get_id() << "ifrunning ok \n ";
}
m_pthreadCond.wait(lck);
}
if (m_shutdown)
{
cout << pThread->mythread.get_id() << "'shutdown " << endl;
lck.unlock();
break;
}
//走到这里,可以取得消息进行处理了【消息队列中必然有消息】,注意,目前还是互斥着呢
char* jobbuf = pThreadPoolObj->m_MsgRecvQueue.front(); //返回第一个元素但不检查元素存在与否
pThreadPoolObj->m_MsgRecvQueue.pop_front(); //移除第一个元素但不返回
--pThreadPoolObj->m_iRecvMsgQueueCount; //收消息队列数字-1
//可以解锁互斥量了
lck.unlock();
//能走到这里的,就是有消息可以处理,开始处理
++pThreadPoolObj->m_iRunningThreadNum; //原子+1【记录正在干活的线程数量增加1】,这比互斥量要快很多
cout << "\t\t" << pThread->mythread.get_id() << "get : " << jobbuf << endl;
delete[]jobbuf;
--pThreadPoolObj->m_iRunningThreadNum; //原子-1【记录正在干活的线程数量减少1】
}
return (void*)0;
}
void CThreadPool::StopAll() //使线程池中的所有线程退出
{
//(1)已经调用过,就不要重复调用了
if (m_shutdown == true)
{
return;
}
m_shutdown = true;
//(2)唤醒等待该条件【卡在pthread_cond_wait()的】的所有线程,一定要在改变条件状态以后再给线程发信号
m_pthreadCond.notify_all();
//(3)等等线程,让线程真返回
std::vector<ThreadItem*>::iterator iter;
for (iter = m_threadVector.begin(); iter != m_threadVector.end(); iter++)
{
(*iter)->mythread.join();
}
//(4)释放一下new出来的ThreadItem【线程池中的线程】
for (iter = m_threadVector.begin(); iter != m_threadVector.end(); iter++)
{
if (*iter)
delete* iter;
}
m_threadVector.clear();
printf("CThreadPool::StopAll()成功返回,线程池中线程全部正常结束!\n");
return;
}
void CThreadPool::inMsgRecvQueueAndSignal(char* buf) //收到一个完整消息后,入消息队列,并触发线程池中线程来处理该消息
{
unique_lock<mutex> lck(m_pthreadMutex);
m_MsgRecvQueue.push_back(buf);
++m_iRecvMsgQueueCount;
lck.unlock();
Call();
return;
}
void CThreadPool::Call() //来任务了,调一个线程池中的线程下来干活
{
m_pthreadCond.notify_one();
}
int main()
{
// 检测是否有内存泄漏
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
CThreadPool* pCThreadPool = new CThreadPool();
pCThreadPool->Create(10);
for (int i = 0; i < 1000; ++i)
{
char* mess = new char[10];
sprintf(mess, "hello %d", i);
pCThreadPool->inMsgRecvQueueAndSignal(mess);
}
Sleep(10000);
// 防止m_shutdown提前 为true, 只是测试用
pCThreadPool->StopAll();
cout << sizeof(CThreadPool) << endl;
delete pCThreadPool;
return 0;
}
- my
#include<iostream>
#include<thread>
#include<mutex>
#include<condition_variable>
#include<vector>
#include<cstring>
#include<algorithm>
#include<string>
#include<Windows.h>
using namespace std;
class CThreadPool {
public:
class CThreadItem {
public:
bool is_running;
thread mythread;
CThreadPool *p_This;
//构造函数
CThreadItem(CThreadPool* pthis) :p_This(pthis), is_running(false) {
cout << this << endl;
}
//析构函数
~CThreadItem() {}
};
static bool m_shutdown; //线程退出标志,false不退出,true退出
int m_iThreadNum;
CThreadPool();
~CThreadPool();
void Stopall();
void Call();
void Creat(int);
void *ThreadFun(void *);
void inMsgRecvQueueAndSignal(char*);
vector<char*> m_msg;
vector<CThreadItem*> m_threadVec;
mutex m_pthreadMutex;
condition_variable m_pthreadCond;
};
bool CThreadPool::m_shutdown = false;
CThreadPool::CThreadPool() {
}
CThreadPool::~CThreadPool() {
lblfor1:
for (auto iter = m_msg.begin(); iter != m_msg.end(); ++iter) {
char* buf = *iter;
delete[]buf;
goto lblfor1;
}
}
void CThreadPool::Call() {
m_pthreadCond.notify_one();
}
void CThreadPool::Stopall() {
if (m_shutdown) {
return ;
}
m_shutdown = true;
m_pthreadCond.notify_all();
for (auto iter = m_threadVec.begin(); iter != m_threadVec.end(); iter++)
{
(*iter)->mythread.join();
}
cout << "------\n";
for (auto iter = m_threadVec.begin(); iter != m_threadVec.end(); iter++)
{
CThreadItem* tmp = *iter;
cout << tmp << endl;
delete tmp;
}
cout << "------\n";
m_threadVec.clear();
printf("cthreadpool::stopall()成功返回,线程池中线程全部正常结束!\n");
return;
}
void CThreadPool::Creat(int num)
{
m_iThreadNum = num;
CThreadItem* pNew;
cout << "------\n";
for (int i = 0; i < m_iThreadNum; ++i)
{
pNew = new CThreadItem(this);
pNew->mythread = thread(&CThreadPool::ThreadFun, this, pNew);
m_threadVec.push_back(pNew);
}
cout << "------\n";
lblfor:
for (auto iter = m_threadVec.begin(); iter != m_threadVec.end(); ++iter)
{
if (!((*iter)->is_running))
{
goto lblfor;
}
}
cout << " Creat ok\n";
}
void *CThreadPool::ThreadFun(void *Data)
{
CThreadItem* pThread = static_cast<CThreadItem*>(Data);
CThreadPool* pool = pThread->p_This;
while (1)
{
unique_lock<mutex> lck(m_pthreadMutex);
while (m_msg.size() == 0 && m_shutdown == false)
{
if (!pThread->is_running) {
pThread->is_running = true;
}
m_pthreadCond.wait(lck);
}
if (m_shutdown)
{
lck.unlock();
return (void*)0;
}
char* jobbuf = m_msg.front();
m_msg.erase(m_msg.begin());
cout << "\t\t\tget:" << jobbuf << endl;
delete []jobbuf;
lck.unlock();
}
return (void*)0;
}
void CThreadPool::inMsgRecvQueueAndSignal(char* rhs)
{
m_pthreadMutex.lock();
m_msg.push_back(rhs);
m_pthreadMutex.unlock();
Call();
}
int main()
{
// 检测是否有内存泄漏
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
CThreadPool* pCThreadPool = new CThreadPool();
pCThreadPool->Creat(10);
for (int i = 0; i < 1000; ++i)
{
char* mess = new char[10];
sprintf(mess, "hello %d", i);
pCThreadPool->inMsgRecvQueueAndSignal(mess);
}
Sleep(5000);
pCThreadPool->Stopall();
cout << sizeof(CThreadPool) << endl;
delete pCThreadPool;
return 0;
}