Qt线程池+生产者消费者模型

简介: Qt线程池+生产者消费者模型

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、模型

image.png

6、Qt多线程(QThread)

Qt多线程是指在Qt框架中使用线程(Thread)来实现并发执行的技术。Qt提供了一套完整的多线程支持,使得开发者能够创建和管理线程,以提高应用程序的性能和响应性。以下是一些关键的技术点:

1. QThread 类:

  - Qt中的线程是通过继承自QThread的类来实现的。

  - 使用QThread可以创建线程,启动线程执行,以及控制线程的运行。


2. 事件循环:

  - 每个线程可以有自己的事件循环,通过QThread::exec()启动。

  - 事件循环允许线程接收和处理事件,例如定时器事件、信号等。


3. 线程安全:

  - 多线程编程中,线程安全是一个重要的考虑因素。

  - Qt提供了多种机制来确保线程安全,例如QMutex、QReadWriteLock、QSemaphore等。


4. 信号和槽:

  - Qt的信号和槽机制支持跨线程通信。

  - 使用Qt::QueuedConnection可以安全地在不同线程之间传递信号和槽。


5. 局部对象:

  - 在线程中创建的局部对象,如QMutexLocker,可以自动管理锁的获取和释放。


6. 线程池:

  - Qt提供了QThreadPool,用于管理一组可重用的线程。

  - 线程池可以提高资源利用率,避免频繁创建和销毁线程。


7. 线程间数据共享:

  - 使用QSharedMemory可以安全地在线程间共享数据。

  - 共享内存需要正确的同步机制来避免竞态条件。


8. 线程间同步:

  - 使用QWaitCondition可以等待某个条件成立。

  - 结合QMutex使用,可以实现线程间的同步。


9. 线程生命周期管理:

  - 通过QThread::quit()和QThread::terminate()可以控制线程的退出。

  - 使用QThread::finished()信号可以知道线程何时结束。


10. 线程优先级:

   - 可以通过QThread::setPriority()设置线程的优先级。


11. 线程局部存储:

   - 使用QThreadStorage可以为每个线程创建独立的局部存储。


12. 线程安全的数据容器:

   - Qt提供了线程安全的数据容器,如QQueue、QStack、QLinkedList等。


13. 线程的创建和销毁:

   - 线程的创建通过QThread的构造函数和start()方法。

   - 线程的销毁需要确保线程已经安全退出,可以通过wait()方法等待线程结束。


14. 线程的异常处理:

   - 需要考虑线程中的异常处理,确保线程异常不会影响整个应用程序的稳定性。


15. 线程的调试和诊断:

   - 使用Qt的调试工具和日志系统可以帮助诊断多线程程序中的问题。

使用Qt进行多线程编程时,需要仔细设计线程的创建、同步、通信和销毁过程,以确保程序的稳定性和效率。同时,要注意避免常见的多线程问题,如死锁、竞态条件等。

相关文章
|
4月前
|
安全 Java 调度
Netty源码—3.Reactor线程模型二
本文主要介绍了NioEventLoop的执行总体框架、Reactor线程执行一次事件轮询、Reactor线程处理产生IO事件的Channel、Reactor线程处理任务队列之添加任务、Reactor线程处理任务队列之执行任务、NioEventLoop总结。
|
4月前
|
安全 Java
Netty源码—2.Reactor线程模型一
本文主要介绍了关于NioEventLoop的问题整理、理解Reactor线程模型主要分三部分、NioEventLoop的创建和NioEventLoop的启动。
|
6月前
|
缓存 NoSQL 中间件
Redis的线程模型
Redis采用单线程模型确保操作的原子性,每次只执行一个操作,避免并发冲突。它通过MULTI/EXEC事务机制、Lua脚本和复合指令(如MSET、GETSET等)保证多个操作要么全成功,要么全失败,确保数据一致性。Redis事务在EXEC前失败则不执行任何操作,EXEC后失败不影响其他操作。Pipeline虽高效但不具备原子性,适合非热点时段的数据调整。Redis 7引入Function功能,支持函数复用,简化复杂业务逻辑。总结来说,Redis的单线程模型简单高效,适用于高并发场景,但仍需合理选择指令执行方式以发挥其性能优势。
170 6
|
9月前
|
Java
Java—多线程实现生产消费者
本文介绍了多线程实现生产消费者模式的三个版本。Version1包含四个类:`Producer`(生产者)、`Consumer`(消费者)、`Resource`(公共资源)和`TestMain`(测试类)。通过`synchronized`和`wait/notify`机制控制线程同步,但存在多个生产者或消费者时可能出现多次生产和消费的问题。 Version2将`if`改为`while`,解决了多次生产和消费的问题,但仍可能因`notify()`随机唤醒线程而导致死锁。因此,引入了`notifyAll()`来唤醒所有等待线程,但这会带来性能问题。
170 1
Java—多线程实现生产消费者
|
11月前
|
并行计算 JavaScript 前端开发
单线程模型
【10月更文挑战第15天】
|
11月前
|
安全 Java
Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧
【10月更文挑战第20天】Java多线程通信新解:本文通过生产者-消费者模型案例,深入解析wait()、notify()、notifyAll()方法的实用技巧,包括避免在循环外调用wait()、优先使用notifyAll()、确保线程安全及处理InterruptedException等,帮助读者更好地掌握这些方法的应用。
145 1
|
2月前
|
安全 算法 Java
Java 多线程:线程安全与同步控制的深度解析
本文介绍了 Java 多线程开发的关键技术,涵盖线程的创建与启动、线程安全问题及其解决方案,包括 synchronized 关键字、原子类和线程间通信机制。通过示例代码讲解了多线程编程中的常见问题与优化方法,帮助开发者提升程序性能与稳定性。
129 0
|
2月前
|
数据采集 监控 调度
干货分享“用 多线程 爬取数据”:单线程 + 协程的效率反超 3 倍,这才是 Python 异步的正确打开方式
在 Python 爬虫中,多线程因 GIL 和切换开销效率低下,而协程通过用户态调度实现高并发,大幅提升爬取效率。本文详解协程原理、实战对比多线程性能,并提供最佳实践,助你掌握异步爬虫核心技术。
|
3月前
|
Java 数据挖掘 调度
Java 多线程创建零基础入门新手指南:从零开始全面学习多线程创建方法
本文从零基础角度出发,深入浅出地讲解Java多线程的创建方式。内容涵盖继承`Thread`类、实现`Runnable`接口、使用`Callable`和`Future`接口以及线程池的创建与管理等核心知识点。通过代码示例与应用场景分析,帮助读者理解每种方式的特点及适用场景,理论结合实践,轻松掌握Java多线程编程 essentials。
226 5
|
7月前
|
Python
python3多线程中使用线程睡眠
本文详细介绍了Python3多线程编程中使用线程睡眠的基本方法和应用场景。通过 `time.sleep()`函数,可以使线程暂停执行一段指定的时间,从而控制线程的执行节奏。通过实际示例演示了如何在多线程中使用线程睡眠来实现计数器和下载器功能。希望本文能帮助您更好地理解和应用Python多线程编程,提高程序的并发能力和执行效率。
213 20

推荐镜像

更多
  • qt