通过互斥锁和条件变量实现队列的无sleep生产与消费

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/FlayHigherGT/article/details/83830956

昨天转了一篇文章将条件变量与互斥锁的结合使用,今天给大家抠出曾经学到的一段高效的处理消息的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的时候)这里推荐看一下这篇篇文章关于互斥锁和条件变量的:            https://blog.csdn.net/FlayHigherGT/article/details/83790972

还有一个知识点为什么要先执行pthread_cond_signal(&cond);再解锁,这里我就不多解释了,也有一片文章给我们做了解释:

https://blog.csdn.net/D_Guco/article/details/78308974?locationNum=1&fps=1

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 clone https://github.com/gt19930910/threadMessageDemo.git

cd threadMessageDemo

mkdir build

cd build

cmake ..

make

./threadmessage

编译截图:

 

猜你喜欢

转载自blog.csdn.net/FlayHigherGT/article/details/83830956
今日推荐