由于案例1采用等待循环方式进行写入,如果更换成案例2的条件多线程方式,效率会大大增加,下面开始写出新的代码吧
主函数
/*
1、封装线程基类XThread控制线程启动和停止;
2、模拟消息服务器线程,接收字符串消息,并模拟处理;
3、通过Unique_lock和mutex互斥方位list<string> 消息队列
4、主线程定时发送消息给子线程;
*/
#include "XMsgSever.h"
#include <sstream>
#include <iostream>
using namespace std;
int main()
{
XMsgSever server;
server.Start();//启动子线程,调了Main入口,进入死循环消费信息了
for (int i = 0; i < 10; i++)
{
stringstream ss;
ss << "msg: " << i + 1;
server.SendMsg(ss.str());
this_thread::sleep_for(500ms);
}
server.Stop();//改用条件变量的时候,停止线程需要做更改,否则死锁等待
printf("All done!\n");
return 0;
}
XMsgSever类头文件,主要增加了Stop()函数重写部分
//XMsgSever.h
#pragma once
#include "XThread.h"
#include <list>
#include <mutex>
class XMsgSever:public XThread
{
public:
//给当前线程发消息
void SendMsg(std::string msg);
void Stop() override;//在子函数中重载
private:
void Main()override;//重写main,override检查名字是否写错
std::list<std::string> msgs_;//消息队列缓冲
std::mutex mux_;//互斥访问消息队列
std::condition_variable cv_;//条件变量
};
XMsgSever类cpp文件,主要更改了类中的Main()函数,等待部分,使用了条件变量
//XMsgSever.cpp
#include "XMsgSever.h"
#include <iostream>
using namespace std;
void XMsgSever::SendMsg(std::string msg)
{//消息生产者
unique_lock<mutex> lock(mux_);//为了保证list的线程安全,加锁
msgs_.push_back(msg);
lock.unlock();
cv_.notify_one();//通知一个入口函数进行
}
void XMsgSever::Stop()
{
//条件变量
is_exit_ = true;
cv_.notify_all();//通知所有线程,避免锁死了
Wait();
}
void XMsgSever::Main()
{//消息消费者
while (!is_exit())
{
//this_thread::sleep_for(10ms);
unique_lock<mutex> lock(mux_);
//cv_.wait(lock);//条件变量等待,条件满足就直接执行。如果这样写,最后可能一直阻塞在这里
cv_.wait(lock, [this] {
cout << "wait cv" << endl;
if (is_exit())return true;//如果退出了,需要退出
return !msgs_.empty(); //有内容,返回false
});//条件变量等待,条件满足就直接执行
if (msgs_.empty())
{//如果没有消息,则continue
continue;
}
while (!msgs_.empty())
{//消息处理业务逻辑
cout << "recv: " << msgs_.front().c_str() << endl;
msgs_.pop_front();
}
}
}
XThread 类头文件中将is_exit_变量设置为了protected,为了在子类中可以访问这个变量
//XThread.h
#pragma once
#include <thread>
//基类
class XThread
{
public:
virtual void Start();//启动线程
virtual void Stop();//设置线程退出标志,并等待
virtual void Wait();//等待
virtual bool is_exit();//线程是否退出
protected:
bool is_exit_ = false;//放到这里来,派生类可以访问这个变量
private:
virtual void Main() = 0;//线程入口,纯虚函数,子函数必须单独实现
std::thread th_;
};
XThread 类cpp文件没有做任何更改
//
#include "XThread.h"
using namespace std;//在CPP中引用using namespace
void XThread::Start()//启动线程
{
is_exit_ = false;//不要退出
th_ = thread(&XThread::Main,this);
}
void XThread::Stop()//设置线程退出标志,并等待
{
is_exit_ = true;
Wait();
}
void XThread::Wait()//等待
{
if (th_.joinable())
{
th_.join();
}
}
bool XThread::is_exit()//线程是否退出
{
return is_exit_;
}
程序可以顺利执行完,执行效果如下图