昨天转了一篇文章将条件变量与互斥锁的结合使用,今天给大家抠出曾经学到的一段高效的处理消息的demo,通过互斥锁实现安全队列,通过条件变量实现队列的工作与休息。
目录结构:
简单介绍:
SignalThread是封装好的线程类,我们所做的核心工作都是在这里完成,其他类也是服务于这里;
MessageList是封装好的安全线程类,基于c++ list实现的;
MessageHanderImp是处理消息的方法,通过继承MessageHander的接口,实现了方法OnMessage,其实只是printf了一下;
message是消息的类,封装了一下我们的消息;
源码解析:
主函数很简单,显而易见SignalThread是我们实现的一个最主要的类,在这里面封装了线程完成了核心功能,主函数只要将它启动即可,之后往封装好的类里面“push”数据,当然这个“push”也是我们封装好的方法postMessage。MessageHanderImp是处理消息的类,message是消息的类。
int main(int argc, char** argv) {
cout << "----start\n";
SignalThread signalThread;
signalThread.start(); //核心线程启动
cout << "----post\n";
signalThread.postMessage(new MessageHanderImp(), new Message());//往线程里面push消息
cout << "----post end\n";
getchar();
return 0;
}
核心代码:
下面是我们实现的核心类SignalThread,注释写的蛮清楚了,类的方法在头文件中直接实现了,其中最重要的是MessageData* hander = m_queue.wait();这边的wait在messageList里面实现。
struct MessageData {
MessageHander* pHander;
Message*pMessage;
};
class SignalThread {
public:
SignalThread() {
pthread_cond_init(&cond, NULL);
pthread_mutex_init(&mutex, NULL);//初始化锁和条件变量
}
virtual ~SignalThread(){
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
}
void start() {
pthread_t t;
pthread_mutex_lock(&mutex);
pthread_create(&t, NULL, run, this);
pthread_cond_wait(&cond, &mutex);//这边等待线程开始时会停止等待
pthread_mutex_unlock(&mutex);
}
void postMessage(MessageHander* hander, Message* message = NULL) {
MessageData * pessageData = new MessageData();
pessageData->pHander = hander;
pessageData->pMessage = message;
m_queue.push_back(pessageData);//实现往队列推送消息
}
private:
void* _start(void * arg) {
while(1){
pthread_mutex_lock(&mutex);
pthread_cond_signal(&cond);//这里是解开主线程的wait
pthread_mutex_unlock(&mutex);
//要改成阻塞式的队列
MessageData* hander = m_queue.wait();//如果没有消息需要进行wait,释放cpu
if(hander){ //一旦有消息及时处理
printf("_start SignalThread OnMessage\n");
hander->pHander->OnMessage(hander->pMessage);//这是一个处理消息的方法
}
}
return NULL;
}
static void *run(void* pths) {
SignalThread* THIS = (SignalThread*)pths;
return THIS->_start(pths);
}
private:
MessageList<MessageData*> m_queue;//这里封装了安全队列,下面讲解
pthread_mutex_t mutex;
pthread_cond_t cond;
};
messageList实现:
这里边实现了模板,最主要就是说一下wait这个方法pthread_cond_wait(&cond, &mutex);实现了阻塞,当队列是空的时候不进行轮询浪费cpu而是wait,至于为什么不用 if (m_msglist.empty()) 而是用 while (m_msglist.empty()) 是因为if (在某些情况下可能会出问题,特别是有多个线程在wait的时候)这里推荐看一下这篇篇文章关于互斥锁和条件变量的: 浅谈互斥锁为什么还要和条件变量配合使用_GT19930910的博客-CSDN博客
还有一个知识点为什么要先执行pthread_cond_signal(&cond);再解锁,这里我就不多解释了,也有一片文章给我们做了解释:
唤醒线程是否要持有锁(Signal With Mutex Locked Or Not?)_D_Guco的博客-CSDN博客
messageList部分代码:
value_type wait()
{
lock();
while (m_msglist.empty())
{
// LOGE("wait ~~~~~~~~~~~~~~~1");
pthread_cond_wait(&cond, &mutex);//直到有信号告知有数据来,才结束等待
}
// LOGE("wait ~~~~~~~~~~~~~~~2");
value_type tmp = m_msglist.front();
m_msglist.pop_front();
unlock();
return tmp;
}
bool push_back(value_type msg_data)
{
lock();
m_msglist.push_back(msg_data);
pthread_cond_signal(&cond);//推送完数据之后通知处理数据
unlock();
return true;
}
github完整代码以及编译方法:
git地址: mytest-projects: 收集一些c/c++的技术点
cd thread-and-message
mkdir build
cd build
cmake ..
make
./threadmessage