C++11消息队列 + Qt线程池 + QRunnable执行任务简单模型

Posted judes

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++11消息队列 + Qt线程池 + QRunnable执行任务简单模型相关的知识,希望对你有一定的参考价值。

1、模板类queue,包含头文件<queue>中,是一个FIFO队列。

queue.push():在队列尾巴增加数据
queue.pop():移除队列头部数据
queue.font():获取队列头部数据的引用
...

2、Qt库的线程池,QThreadPool

QThreadPool.setMaxThreadCount():设置线程池最大线程数
QThreadPool.start(new QRunnable(..)):开启线程池调用QRunnable

3、QRunnable执行任务

void run();//重写虚函数,在里面消费任务队列
setAutoDelete(true)//默认就是true,消费结束自动回收内存

4、代码

run.h

#ifndef RUN_H
#define RUN_H

#include <QObject>
#include <QRunnable>
#include <string>
#include <iostream>

struct MyString

    std::string valueStr;
;

class Run : public QObject , public QRunnable

    Q_OBJECT
public:
    Run() = default;
    Run(const MyString& myString);
protected:
    ~Run() = default;
    void run();
signals:

public slots:

private:
    MyString myString;
;

#endif // RUN_H

说明:
MyString结构体代替实际项目中的任务,Run接口的run纯虚函数用来消费分配来的MyString
run.cpp
#include "run.h"
#include <QThread>
#include <QDebug>
Run::Run(const MyString &myString)

    this->myString = myString;
    //this->setAutoDelete(true);//默认就是true


void Run::run()

    //std::cout << "value:" << this->myString.valueStr <<";调用线程ID为:" << QThread::currentThread() << std::endl;
    qDebug() << "value:" << QString::fromStdString(myString.valueStr) << "thread:" << QThread::currentThreadId();
    QThread::msleep(100);

说明:不使用cout打印是因为,cout打印不是原子操作,可能多个字符串被杂糅在一起打印;qDebug不会,应该底层加了锁

main.cpp

#include <QCoreApplication>
#include "run.h"
#include <queue>
#include <mutex>
#include <QThreadPool>
#include <thread>
using namespace std;
queue<MyString> myList;
mutex myMutex;
volatile bool addThreadIsEnd = false;
void makeListThread();
int main(int argc, char *argv[])
   
    QCoreApplication a(argc, argv);
    cout << "begin main" << endl;
    thread addThread(makeListThread);
    addThread.detach();
    cout << "begin addThread" << endl;
    QThreadPool tp;
    tp.setMaxThreadCount(20);
    cout << "begin threadPool" << endl;
    while(true)
    
        if(!myList.empty())
        
            MyString tempMyString = myList.front();
            tp.start(new Run(tempMyString));
            myMutex.lock();
            myList.pop();
            myMutex.unlock();
        
        else
        
            if(addThreadIsEnd)
            
                break;
            
            else
            
                QThread::msleep(10);
            
        
    
    cout << "end main,list size:" << myList.size() << endl;
    return a.exec();


void makeListThread()

    string a;
    MyString tempMyString;
    for(int i=0;i<10000;i++)
    
        QThread::msleep(0);
        a = to_string(i);
        tempMyString.valueStr = a;
        myMutex.lock();
        myList.push(tempMyString);
        myMutex.unlock();
    
    addThreadIsEnd = true;
    cout << "end addThread" << endl;
5、模型
技术图片

 6、其他说明

6.1、假设线程池大小有n个,那么这n个线程在线程池初始化的时候就已经定了,即n个线程id是恒定的,队列永远由这n个线程消费

6.2、std::queue非线程安全,同时往队列加任务、取任务可能会触发线程安全问题;同时删除头任务、访问头任务也可能会触发线程安全问题,需要加线程锁

6.3、tp.start(new Run(tempMyString));这里new了一个没有指针指向的Runnable对象,在哪里回收的呢?Run.setAutoDelete(true)自动回收

 

以上是关于C++11消息队列 + Qt线程池 + QRunnable执行任务简单模型的主要内容,如果未能解决你的问题,请参考以下文章

随笔——消息队列线程池模型如何保证重启时消息不丢

如何并行运行 Qt GUI 和 Linux 消息队列接收线程?

日志池

Linux入门多线程(线程概念生产者消费者模型消息队列线程池)万字解说

C++11实现半同步半异步的线程池

2020-11-20 Qt事件循环