精华内容
下载资源
问答
  • Qt线程池+多线程使用

    2018-05-31 11:51:17
    保证线程安全的Qt线程池使用线程任务可以和其他线程通信,使用场景:频繁操作的I/O操作或是耗时操作。
  • 使用qt线程池实现多线程http请求,支持限速下载,可以设置全部下载的网络上限,和单个线程的网络上限。可以实时显示当前下载速度。
  • Qt 使用线程池 构建 多线程 多任务 代码是自己写的小demo 可以直接运行
  • 本示例程序使用Qt Creator创建多线程示例,下载下来可直接编译运行: 1.继承QObject 2.继承QThread 3.继承QObject魔改 教程地址: https://tangxing.blog.csdn.net/article/details/111615381
  • 线程池的方式ping ip地址,多线程技术
  • 我们一般使用该类和QThreadPool来在另一个独立的线程中执行该代码。并且,如果QRunnable对象的autoDelete()设为true的话,QThreadPool会在run()运行结束后自动删除该对象。 下边是一个例子,我们会有个任务放到...

    QRunnable类在Qt中是所有可运行对象的基类,代表了由run()函数表示的一个任务或一段要执行的代码。我们一般使用该类和QThreadPool来在另一个独立的线程中执行该代码。并且,如果QRunnable对象的autoDelete()设为true的话,QThreadPool会在run()运行结束后自动删除该对象。

    下边是一个例子,我们会有多个任务放到线程池中执行。

    任务类:

    class Task : public QRunnable
    {
    public:
        Task();
        void run();
    };

    任务添加到线程池中:
        Task* task = new Task();
        task->setAutoDelete(true);
        QThreadPool::globalInstance()->start(task);

     

    展开全文
  • * 支持多线程,保证获取到的连接一定是没有被其他线程正在使用 * 按需创建连接,可以创建多个连接,可以控制连接的数量 * 连接被复用,不是每次都重新创建一个新的连接(连接的创建是一个很消耗资源的过程) * ...
  • 而在日常开发中,内存资源是及其宝贵的,所以,我们这里就有了本篇文章QT 多线程线程池QThreadPool。在程序逻辑中经常会碰到需要处理大批量任务的情况,比如密集的网络请求,或者日志分析等等。一般会创建一个队列...

    在一个应用程序中,我们需要多次使用线程,也就意味着,我们需要多次创建并销毁线程。而创建并销毁线程的过程势必会消耗内存。而在日常开发中,内存资源是及其宝贵的,所以,我们这里就有了本篇文章QT 多线程之线程池QThreadPool。在程序逻辑中经常会碰到需要处理大批量任务的情况,比如密集的网络请求,或者日志分析等等。一般会创建一个队列,用一个或者多个线程去消费这个队列,一般也要处理队列的加锁和解锁的问题。

    详解QThreadPool线程池过程中,给大家举栗出线程池优点和运行的注意事项以及示例Demo。

    本文作者原创,转载请附上文章出处与本文链接。

    QT 多线程之线程池QThreadPool(深入理解)目录

    1. 线程池的优点

    2. QT线程池函数

    3. 程序基本界面

    4. 类说明

    QThreadPool类:

    QRunnable类:

    5. 示例Demo

    6. 其它线程文章


    1. 线程池的优点

    • 创建和销毁线程需要和OS交互,少量线程影响不大,但是线程数量太大,势必会影响性能,使用线程池可以这种开销;
    • 线程池维护一定数量的线程,使用时,将指定函数传递给线程池,线程池会在线程中执行任务;

    2. QT线程池函数

    int activeThreadCount() const //当前的活动线程数量
    
    void clear()//清除所有当前排队但未开始运行的任务
    
    int expiryTimeout() const//线程长时间未使用将会自动退出节约资源,此函数返回等待时间
    
    int maxThreadCount() const//线程池可维护的最大线程数量
    
    void releaseThread()//释放被保留的线程
    
    void reserveThread()//保留线程,此线程将不会占用最大线程数量,从而可能会引起当前活动线程数量大于最大线程数量的情况
    
    void setExpiryTimeout(int expiryTimeout)//设置线程回收的等待时间
    
    void setMaxThreadCount(int maxThreadCount)//设置最大线程数量
    
    void setStackSize(uint stackSize)//此属性包含线程池工作线程的堆栈大小。
    
    uint stackSize() const//堆大小
    
    void start(QRunnable *runnable, int priority = 0)//加入一个运算到队列,注意start不一定立刻启动,只是插入到队列,排到了才会开始运行。需要传入QRunnable ,后续介绍
    
    bool tryStart(QRunnable *runnable)//尝试启动一个
    
    bool tryTake(QRunnable *runnable)//删除队列中的一个QRunnable,若当前QRunnable 未启动则返回成功,正在运行则返回失败
    
    bool waitForDone(int?<i>msecs</i>?=?-1)//等待所有线程运行结束并退出,参数为等待时间-1表示一直等待到最后一个线程退出

    3. 程序基本界面

    4. 类说明

    QThreadPool类:

    用来管理 QThreads,经过测试QThreadPool线程池函数并不是安全线程,多个线程操作还是会出现抢资源现象,同步还是需要互斥锁或者信号量来同步。

    主要属性:
    
    1、activeThreadCount: 此属性表示线程池中的活动线程数,通过activeThreadCount() 调用。
    2、expiryTimeout: 线程活着的时间。没有设置expiryTimeout毫秒的线程会自动退出,此类线程将根据需要重新启动。默认的expiryTimeout为30000毫秒 (30 秒)。如果expiryTimeout为负, 则新创建的线程将不会过期, 在线程池被销毁之前, 它们将不会退出。通过expiryTimeout()调用,通setExpiryTimeout(int expiryTimeout)设置 。
    3、maxThreadCount : int 表示线程池使用的最大线程数。
    通过maxThreadCount() 调用,通过setMaxThreadCount(int maxThreadCount) 设置
    注意:即使maxThreadCount限制为零或为负数, 线程池也至少有1个线程。
    
    主要成员函数
    
    QThreadPool *QThreadPool::globalInstance()
    
    返回Qt应用程序全局线程池实例。
    
    void reserveThread()
    
    预约一个线程,这个函数总是会增加活动线程的数量。这意味着通过使用这个函数,activeThreadCount()可以返回一个大于maxThreadCount()的值。
    
    void releaseThread()
    
    释放以前通过调用reserveThread()预约的线程。
    如果不先预约一个线程,调用这个函数会临时增加maxThreadCount()。当线程进入休眠等待时,能够允许其他线程继续。
    要记得在完成等待时调用reserveThread(),以便线程池可以正确控制activeThreadCount()。
    
    void QThreadPool :: start(QRunnable * runnable,int priority = 0)
    
    在任务数量小于maxThreadCount时,为每个runnable任务预约一个线程。超过maxThreadCount时,将任务放入运行队列中。priority 参数用来设置线程运行优先级。
    
    bool tryStart(QRunnable *runnable)
    
    此方法尝试预约一个线程来运行runnable。
    如果在调用的时候没有线程可用,那么这个函数什么都不做,并返回false。否则,将使用一个可用线程立即运行runnable,并返回此函数true。
    
    void clear()
    
    用于删除在任务队列中,还没有启动的任务。
    
    bool tryTake(QRunnable *runnable)
    
    如果runnable任务还没开始运行,那么从队列中删除此runable任务,此时函数返回true;如果runnable任务已经运行,返回false。
    只用来删除runnable->autoDelete() == false的runnable任务,否则可能会删错任务.
    
    bool waitForDone(int msecs = -1)
    
    等待msecs毫秒, 以便所有线程退出并从线程池中移除所有线程。如果删除了所有线程, 则返回true ,否则, 它将返回false。默认等待时间为-1,即等待最后一个线程退出。
    
    内容出自: https://blog.csdn.net/y396397735/article/details/78637634

    QRunnable类:

    是所有runable对象的基类。
    QRunnable类是一个接口, 用于表示需要执行的任务或代码段, 具体任务在run() 函数内部实现。

    可以使用QThreadPool在各个独立的线程中执行代码。如果autoDelete() 返回true (默认值), QThreadPool将自动删除QRunnable 。使用setAutoDelete() 可更改是否自动删除。

    QThreadPool 是创建线程池函数,QRunnable是线程池的线程具体执行操作函数。两者要搭配使用。

    主要成员函数
    
    bool autoDelete() const
    
    获取自动删除是否启用,启用返回true,未启用返回false。
    
    virtual void run() = 0
    
    纯虚函数,在QRunnable子类中实现详细任务处理逻辑。
    
    void setAutoDelete(bool autoDelete)
    
    如果autoDelete为 true, 则启用自动删除。否则自动删除将被禁用。
    如果启用了自动删除, QThreadPool将在调用 run () 函数返回后自动删除此runable对象。否则, runable对象所有权不属于线程池,由开发人员管理。
    请注意, 必须先设置此标志,(默认构造函数已经将其设置为true),然后才能调用QThreadPool:: start()。在QThreadPool:: start() 之后调用此函数将导致不可预测后果。
    
    内容出自:https://blog.csdn.net/y396397735/article/details/78637634

    5. 示例Demo

    mythread.h

    #ifndef MYTHREAD_H
    #define MYTHREAD_H
    #include <QRunnable>
    #include <QObject>
    #include <QDebug>
    #include <QReadWriteLock>
    #include <QTime>
    #include <QSemaphore>
    
    class mythread : public QObject, public QRunnable
    {
            Q_OBJECT
    public:
        mythread();
    
    
        //QThread的虚函数
        //线程处理函数
        //不能直接调用,通过start()间接调用
        void run();
    
    signals:
        void isDone(int);   //处理完成信号
        void mySignal();    //注意!要使用信号,采用QObejct 和 QRunnable多继承,记得QObject要放在前面
    
    public slots:
        //接收主线程的消息
        void recMegFromMain(QString);
    };
    
    class mythread1 : public QObject, public QRunnable
    {
        Q_OBJECT
    public:
    
        void run();
    
    };
    
    class mythread2  : public QObject, public QRunnable
    {
        Q_OBJECT
    public:
    
        void run();
    };
    
    
    class mythread3  : public QObject, public QRunnable
    {
        Q_OBJECT
    public:
    
        void run();
    };
    
    class mythread4  : public QObject, public QRunnable
    {
        Q_OBJECT
    public:
    
        void run();
    };
    #endif // MYTHREAD_H
    

    mythread.cpp

    #include "mythread.h"
    #include <QMutex>
    #include <QRandomGenerator>
    #include <QWaitCondition>
    #include <QThread>
    /*
    如果乱码就加上QStringLiteral();
    
    #pragma execution_character_set("GB2312")
    */
    mythread::mythread()
    {
    
    }
    void mythread::run()
    {
    
    
        for(int i=0;i<10;i++){
            //QThread::sleep(2);
            qDebug()<< QStringLiteral("PrintTask run 被调用,调用线程ID为:") << QThread::currentThread() << QStringLiteral( " 线程1打印数据:") <<QString::number(i);
        }
        //emit isDone(1);  //发送完成信号
    }
    void mythread::recMegFromMain(QString str)
    {
        qDebug()<< "子线程接收到" <<str;
    }
    
    void mythread1::run()
    {
    
        qDebug()<< QStringLiteral("PrintTask run 被调用,调用线程ID为:") << QThread::currentThread() ;
        for(int i=10;i<20;i++){
            QThread::sleep(2);
            qDebug()<< "线程2打印数据:" <<QString::number(i);
        }
        //emit isDone(1);  //发送完成信号
    }
    
    void mythread2::run()
    {
    
        qDebug()<< "PrintTask run 被调用,调用线程ID为:" << QThread::currentThread() ;
        for(int i=20;i<30;i++){
            QThread::sleep(2);
            qDebug()<< "线程3打印数据:" <<QString::number(i);
        }
        //emit isDone(1);  //发送完成信号
    }
    
    void mythread3::run()
    {
    
        qDebug()<< "PrintTask run 被调用,调用线程ID为:" << QThread::currentThread() ;
        for(int i=30;i<40;i++){
            QThread::sleep(2);
            qDebug()<< "线程4打印数据:" <<QString::number(i);
        }
        //emit isDone(1);  //发送完成信号
    }
    
    void mythread4::run()
    {
    
        qDebug()<< "PrintTask run 被调用,调用线程ID为:" << QThread::currentThread() ;
        for(int i=40;i<50;i++){
            QThread::sleep(2);
            qDebug()<< "线程5打印数据:" <<QString::number(i);
        }
        //emit isDone(1);  //发送完成信号
    }
    

    mainwindow.h

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    #include "mythread.h"
    #include <QDebug>
    #include <QMessageBox>
    #include <QThreadPool>
    QT_BEGIN_NAMESPACE
    namespace Ui { class MainWindow; }
    QT_END_NAMESPACE
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        MainWindow(QWidget *parent = nullptr);
        ~MainWindow();
    
        void dealDone();   //线程槽函数
    
        void mySlot();
    
        void receiveMsgFromThread(int);
    
        void sengMsgToThreadBtn();
    private:
        Ui::MainWindow *ui;
    
        QThreadPool pool;
    
        mythread* task = new mythread();
        mythread1* task1 = new mythread1();
        mythread2* task2 = new mythread2();
        mythread3* task3 = new mythread3();
        mythread4* task4 = new mythread4();
    signals:
        //给子线程发消息
        void sengMsgToThread(QString);
    private slots:
        void on_pushButton_clicked();
        void on_pushButton_2_clicked();
        void on_pushButton_3_clicked();
        void on_pushButton_4_clicked();
        void on_pushButton_5_clicked();
        void on_pushButton_6_clicked();
        void on_pushButton_7_clicked();
        void on_pushButton_8_clicked();
    };
    #endif // MAINWINDOW_H
    

    mainwindow.cpp

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    
    #include <QReadWriteLock>
    
    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
        , ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        //设置最大线程数为3的一个线程池
        pool.setMaxThreadCount(5);
    
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    void MainWindow::sengMsgToThreadBtn()
    {
        emit sengMsgToThread("hello");
    }
    // 定义槽函数 mySlot()
    void MainWindow::mySlot()
    {
        QMessageBox::about(this,"Tsignal", "响应线程中的mySlot函数");
    }
    //接收线程函数
    void MainWindow::receiveMsgFromThread(int i)
    {
        QString str = QString::number(i);
        qDebug()<<str;
    }
    void MainWindow::dealDone()
    {
        ui->label->setText("线程停止");
        //停止线程
    
    }
    
    void MainWindow::on_pushButton_clicked()
    {
    
        //QThread::sleep(1);
        //pool.waitForDone();           //等待任务结束
        on_pushButton_4_clicked();
        on_pushButton_5_clicked();
        on_pushButton_6_clicked();
        on_pushButton_7_clicked();
        on_pushButton_8_clicked();
    
        //启动线程,处理数据
        ui->label->setText("start");
    
    }
    
    void MainWindow::on_pushButton_2_clicked()
    {
        //pool.releaseThread();
        //停止线程
        //dealDone();
        //sengMsgToThreadBtn();
    }
    
    void MainWindow::on_pushButton_3_clicked()
    {
        qDebug() <<pool.activeThreadCount();
        //sengMsgToThreadBtn();
    }
    
    void MainWindow::on_pushButton_4_clicked()
    {
        pool.start(task);             //任务放进线程池
        task->setAutoDelete(false);
    }
    
    void MainWindow::on_pushButton_5_clicked()
    {
        pool.start(task);             //任务放进线程池
        task->setAutoDelete(false);
        /*
        pool.start(task1);
        task1->setAutoDelete(false);
        */
    }
    
    void MainWindow::on_pushButton_6_clicked()
    {
        pool.start(task);             //任务放进线程池
    
        //pool.start(task2);
    }
    
    void MainWindow::on_pushButton_7_clicked()
    {
        pool.start(task);             //任务放进线程池
        //pool.start(task3);
    }
    
    void MainWindow::on_pushButton_8_clicked()
    {
        pool.start(task);             //任务放进线程池
        //pool.start(task4);
    }
    

    这个已经是比较完整的项目了,下载地址:https://download.csdn.net/download/qq_37529913/16604442

    6. 其它线程文章

    以下文章均为作者原创文章,看完记得收藏、关注加👍

    QT 初识线程(简单实现):https://blog.csdn.net/qq_37529913/article/details/110127940

    QT QMutex使用详解:https://blog.csdn.net/qq_37529913/article/details/110187452

    QT 线程之QSemaphore(深入理解):https://blog.csdn.net/qq_37529913/article/details/110187121

    QT线程 Emit、Sgnals、Slot详细解释:https://blog.csdn.net/qq_37529913/article/details/110211435

    QT 线程之QWaitCondition(深入理解):https://blog.csdn.net/qq_37529913/article/details/110212704

    Qt 多线程之线程事件循环(深入理解):https://blog.csdn.net/qq_37529913/article/details/110229382

    QT线程之QObjects(深入理解):https://blog.csdn.net/qq_37529913/article/details/110228837

    QT线程之可重入与线程安全(深入理解):https://blog.csdn.net/qq_37529913/article/details/110224166

    QT 主线程子线程互相传值:https://blog.csdn.net/qq_37529913/article/details/110506178

    QT线程同步与异步处理:https://blog.csdn.net/qq_37529913/article/details/110521759

    QT 多线程之线程池QThreadPool(深入理解):https://blog.csdn.net/qq_37529913/article/details/115536799

    QT之浅拷贝、深拷贝、隐式共享(深度理解必看文章):https://blog.csdn.net/qq_37529913/article/details/110235596

    QT 隐式共享机制对STL样式迭代器的影响:https://blog.csdn.net/qq_37529913/article/details/110252454

     

     

    展开全文
  • 自已用Qt写的多线程服务器实现功能,用QtcpSocket进行通讯,可以正常编译运行,很适合初学者学习使用
  • QT 多线程 线程池 QRunnalbe QThreadPool

    千次阅读 2019-03-19 17:22:22
    QT中线程很早就出现了,多线程使用目的是为了减轻主线程压力,不至于主线程界面卡顿,提高用户体验。但是线程的创建与销毁需要与系统交互,会产生很大的开销。若需要频繁的创建线程就建议使用线程池,有线程池...

    一、背景

            QT中线程很早就出现了,多线程的使用目的是为了减轻主线程压力,不至于主线程界面卡顿,提高用户体验。但是线程的创建与销毁需要与系统交互,会产生很大的开销。若需要频繁的创建线程就建议使用线程池,有线程池维护一定数量的线程,当需要进行多线程的运算时,将运算函数传递给线程池即可。线程池会根据可用线程进行任务安排。

    线程池有什么作用呢?

    一个作用就是限制系统中执行线程的数量。根据系统的环境情况,可以自动或手动设置线程数量,达到运行的最佳效果;少了浪费了系统资源,多了造成系统拥挤效率不高。用线程池控制线程数量,其他线程排队等候。一个任务执行完毕,再从队列的中取最前面的任务开始执行。若队列中没有等待进程,线程池的这一资源处于等待。当一个新任务需要运行时,如果线程池中有等待的工作线程,就可以开始运行了;否则进入等待队列。

    为什么要是用线程池?

    1.减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
    2.可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。

    二、相关类

    在QT中使用多线程,可以使用QThread。但是如果使用线程池可以使用QRunnable + QThreadPool 

    QRunnable 是所有的runnable对象的基类,是一个接口,用于表示一个任务或者要执行的代码,需要重新实现void run()函数。

    QThreadPool类用于管理QThreads集合,管理和循环使用单独的QThread对象,以帮助程序减少创建线程的成本。每一个QT应用程序都有一个全局的QThreadPool对象,可以通过globalInsatance()获取。

    QThreadPool *thradPool = QThreadPool::globalInstance();//获取全程线程池

    1.QRunnable :

    所有的需要在子线程进行的计算或者任务,都需要在继承于QRunnable的类里,然后重新实现void run()函数。最后生成一个对象runnableObj,扔给线程池。

    QThreadPool::globalInstance()->start(runnableObj);//扔给线程池

    类成员函数:

    void setAutoDelete(bool autoDelete);//设置是否自动删除。默认是自动删除。运行完后,由线程池自动删除对象。

    2.QThreadPool:线程池类

    类成员函数:

    int activeThreadCount() const //当前的活动线程数量
    
    void clear()//清除所有当前排队但未开始运行的任务
    
    int expiryTimeout() const//线程长时间未使用将会自动退出节约资源,此函数返回等待时间默认30秒
    
    int maxThreadCount() const//线程池最大线程数量
    
    void releaseThread()//释放被保留的线程
    
    void reserveThread()//保留线程,此线程将不会占用最大线程数量,从而可能会引起当前活动线程数量大于最大线程数量的情况
    
    void setExpiryTimeout(int expiryTimeout)//设置线程回收的等待时间
    
    void setMaxThreadCount(int maxThreadCount)//设置最大线程数量
    
    void setStackSize(uint stackSize)//此属性包含线程池工作线程的堆栈大小。
    
    uint stackSize() const//堆大小
    
    void start(QRunnable *runnable, int priority = 0)//加入一个运算到队列,注意start不一定立刻启动,只是插入到队列,排到了才会开始运行。需要传入QRunnable ,后续介绍
    
    bool tryStart(QRunnable *runnable)//尝试启动一个任务,成功就返回true
    
    bool tryTake(QRunnable *runnable)//删除队列中的一个QRunnable,若当前QRunnable 未启动则返回成功,正在运行则返回失败
    
    bool waitForDone(int msecs)//等待所有线程运行结束并退出,参数为等待时间-1表示一直等待到最后一个线程退出

    三、一些要解释的事情

    • QThread::idealThreadCount 函数,会根据当前设备的硬件情况给出一个默认的线程数量,而线程池的默认最大线程数就是此值,maxThreadCount.
    • 由于reserveThread 后的线程不计入线程最大数量;因此,可能出现activeThreadCount > maxThreadCount的情况。
    • QThreadPool中的start()函数里,传入的是QRunnable对象指针,传入后,线程池会调用QRunnable的autoDelete()函数。若返回true,则当此运算完成后自动释放内容、空间,不需要后续主动判断是否完成并释放空间。
    • tryStart(),若返回成功,不会自动释放内容,需要调用方主动释放,无论aotudelete返回值是什么。返回false,也不会主动delete
    • 对于tryStart() 如果返回成功,则等同于start(). 若返回false,则不会自动delete.
    • 对于autoDelete必须在start/tryStart之前设置,不要在调用之后修改,否则结果不可预测。

    四、全局线程池

    QThreadPool,提供一个静态函数,QThreadPool::globalInstance(),返回一个当前进程的全局线程池,可在多个类中共同使用一个线程池。也可以新建一个线程池。

    五、基本运用

    要使用线程池,先要子类化一个QRunnable并实现run()虚函数。然后创建一个对象,并把它传给QThreadPool::start(),这会把可运行对象的拥有权赋权给QT的全局线程池,并让他可以开始运行。

    class HelloWorldTask : public QRunnable
    {
        void run() {
            qDebug() << "Hello world from thread " << QThread::currentThread();
        }
    }
     
    HelloWorldTask *hello = new HelloWorldTask();
     
    // QThreadPool取得所有权,并自动删除 hello
    
    QThreadPool::globalInstance()->start(hello);

    默认情况下,可运行对象结束时,线程池会自动将其删除,这也正是我们想要的结果。在某些情况下,如果必须有我们自己负责删除可运行对象时,可以通过调用QRunnable::setAutoDelete(false)来阻止自动删除的发生。

    六、自定义信号槽

    打开QRunnable的头文件时,我们会发现,它不是继承于QObject,也就是说无法使用QObject的特性,例如,信号槽,事件等,为了方便使用,我们可以继承QObject:

    
    class HelloWorldTask : public QObject, public QRunnable
    {
        Q_OBJECT
     
    // 自定义信号
    signals:
        void finished();
     
    public:
         void run() {
             qDebug() << "Hello Thread : " << QThread::currentThreadId();
             emit finished();
         }
    };

    使用时,连接信号槽就行:

    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
     
    public:
        explicit MainWindow(QWidget *parent = 0)
            : QMainWindow(parent)
        {
            qDebug() << "Main Thread : " << QThread::currentThreadId();
     
            // ...
            HelloWorldTask *hello = new HelloWorldTask();
            connect(hello, SIGNAL(finished()), this, SLOT(onFinished()));
            QThreadPool::globalInstance()->start(hello);
            // ...
        }
     
    protected:
        void closeEvent(QCloseEvent *event) {
            if (QThreadPool::globalInstance()->activeThreadCount())
                QThreadPool::globalInstance()->waitForDone();
     
            event->accept();
        }
     
    private slots:
        void onFinished() {
            qDebug() << "SLOT Thread : " << QThread::currentThreadId();
        }
    };

    七、QThread与QRunnable+QThreadPool适用的场景

            QThread是QT的线程类,通过继承QThread然后重写run函数即可实现一个线程类。QThreadPool+ QRunnable配合构建线程池的方法也可以实现线程。我们通过以下问题对上述两种构建线程的方法进行分析和说明。

        (1)既然QThread这么简单我们为什么还要使用QThreadPool + QRunnable创建线程池的方法来使用线程机制呢?

    主要原因:当线程任务量非常大的时候,如果频繁的创建和释放QThread会带来比较大的内存开销,而线程池则可以有效避免该问题,相关的基础支持可以自行百度线程池的优点。

        (2)QThread与 QThreadPool + QRunnable分别适用于哪种应用场景?

         QThread适用于那些常驻内存的任务。而且QThread可以通过信号/槽的方式与外界进行通信。而QRunnable则适用于那些不常驻内存,任务数量比较多的情况。

     

    八、QRunnable 如何与外界进行通信

           方法1:QRunnable并不继承自QObject类,因此无法使用信号/槽的方式与外界进行通信。我们就必须的使用其他方法,这里给大家介绍的是使用:QMetaObject::invokeMethod()函数。

           方法2:使用多重继承的方法,任务子类同时继承自QRunnable和QObject。

    展开全文
  • 一个自己做的基于ffmpeg+QT+多线程知识的播放器代码,开发环境为VS2017,解压后双击sln文件后编译成功可以直接运行,该播放器为入门代码,大佬勿喷
  • QT多线程简单使用

    2020-07-29 00:30:38
    QT多线程相较于Linux/Unix的pthread和C++11...关于每一种方法的优缺点可以查看这位博主的总结Qt使用线程的几种方式及区别,因为项目中使用多线程不需要频繁的创建和销毁,所以使用了第三种方法moveToThread方法。

    在QT中创建一个线程的方法有很多,与std::thread最为接近的是QtConcurrent。QT中有四个创建线程的方法分别是:

    • 继承QThread对象

    • moveToThread方法

    • QRunnable方法

    • QtConcurrent::run方法

    下面是对各种方法的优缺点总结:

    方法用法注意事项优点缺点
    继承QThread创建一个继承QThread的类并重写run方法,调用start方法启动run函数返回线程结束,除非你调用exec()方法; 槽函数应于原对象实现而不是派生的QThread类QThread方便了本线程的管理及与其它线程的通信使用很麻烦:继承+重写,需要自己回收线程资源
    QObject::moveToThread创建一个自定义的QObject并使用方法moveToThread,调用start方法启动自定义QObject不应该有基类QThread方便了本线程的管理及与其它线程的通信,相对于继承QThread没这么麻烦使用较麻烦且有限制(不能有基类),需要自己回收线程资源
    继承QRunnable创建一个继承QRunnable的类并重写run方法,借助QThreadPool方法tryStart(QRunnable)启动QThreadPool可以多次启动QRunnable但是如果设置了autoDelete不建议这么做可以多次启动同一个线程,自动回收资源要使用信号与槽进行通信,需要多继承或者其他方法
    QtConcurrent::run(最简单)往run传入一个函数对象,立即启动线程函数可能无法立即执行使用最简单,扩展性好,无需使用底层的同步原语,可以有返回值线程可能无法立即执行,不需要自己回收线程资源,与std::thread最为接近

    为了方便使用Qt的信号与槽机制,我们常常采用表格的前两种方法,即继承QThread或者使用moveToThreafd方法;如果你没有用到信号与槽,那么你完全可以采用std::thread或者QtConcurrent::run方法。

    本文讲述的是使用QThread进行管理线程创建方法,也就是上述表格的前两个。在使用之前首先需要对QThread的类有一定的理解:

    一、QThread管理

    QThread类是QT提供的一个与平台无关的管理线程的类。一个QThread对象管理一个程序中的线程,run函数是实际执行的内容。默认情况下,run将会通过的调用exec()来启动事件循环并在线程内启动事件循环。

    在介绍这个方法之前有必要对QThread对象做个简单的介绍。以下内容属于搬运[1]:

    1.1 槽函数

     void quit();//Equivalent to calling QThread::exit(0)
     void start(QThread::Priority priority = InheritPriority);
     void terminate();
    

    quit() 停止线程的事件循环。如果线程没有事件循环等于什么都不做。

    start() 开启线程。开启线程将会调用run()方法,操作系统将会根据优先级安排线程的执行,如果一个线程已经被运行,那么槽函数将不会做任何事情。

    terminate() 终止一个线程。线程不一定会立刻终止,这取决于操作系统的调度策略,在调用terminate()后使用QThread::wait() ,wait()函数和POSIX的 pthread_join() 功能是一样的。不推荐使用,因为线程的资源可能因为你的强制终止而永远得不到释放。

    1.2 信号

    void finished();
    void started();
    

    finished() 如果相关线程完成了执行将会发出此信号。这意味着事件循环将只剩下延迟删除的事件。注意,如果你调用terminate()是否会发出这个信号是不一定的,他是一个内部信号。

    started() 相关线程在run()函数被调用之前将发出此信号。

    1.3 受保护的函数

    int exec();
    virtual void run();
    

    exec() 的调用将会使得线程进入事件循环,直到exit()被调用,如果exit退出时是调用quit将会返回一个0值,这个函数被设计在run中自动开启的,我们无需在开启事件循环手动调用。

    1.4 其他重要公共函数

    void exit(int returnCode=0);
    bool wait(unsigned long time = ULONG_MAX);
    void setPriority(QThread::Priority priority)
    

    exit() 通知线程循环以指定返回码退出。通过QEventLoop::exec()退出事件循环。和C++语言一样,0表示正常退出,非零表示有错误。事件循环将会停止,直至再次调用QThread::exec()。

    wait() 将会阻塞至满足下面两个条件的其中一个:

    • 线程执行完毕。run()返回或者线程尚未开始
    • 定时结束。默认是永远不会返回,也就是只能是顶一个,当然你设置了超时时间,那么将会返回一个false并结束阻塞。

    下面是状态指示:

    bool isFinished();
    bool isRunning()const;
    

    下面这个是用来优雅退出一个线程的方法:

    bool isInterruptionRequested()const;
    void requestInterruption();
    

    具体用法参照这里

    1.5 重要静态方法

    void sleep(unsigned long secs);
    void msleep(unsigned long msecs);
    void usleep(unsigned long usecs);
    int QThread::idealThreadCount()
    

    返回 idealThreadCount()当前处理器的最佳线程数。

    二、继承QThread方法

    #include <QCoreApplication>
    #include <QThread>
    #include <QDebug>
    
    class MyThread:public QThread{
        protected:
            void run() override;
    };
    
    void MyThread::run()
    {
        int i=0;
        for(int j=0;j<10;j++)
        {
            qDebug()<<i++;
            QThread::sleep(1);
        }
        qDebug()<<"线程退出成功";
    }
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    
        MyThread * pMythread=new MyThread;
        pMythread->start();
        QObject::connect(pMythread,&QThread::finished,[&a](){a.exit();});
    
        return a.exec();
    }
    

    运行结果如下:
    在这里插入图片描述

    三、QObject::moveToThread方法


    [1] https://blog.csdn.net/luoyayun361/article/details/97150788

    [20200729] 一个对象moveToThread后,对该对象所有操作都是在新的线程中执行的。如一个对象k移入新线程中,之后调用a b方法中打印QThread::currentThreadId()都是同一个。
    [20211022] 更新了Qt几种创建线程的方法及其优缺点分析

    展开全文
  • Qt多线程/线程池

    2020-05-11 22:28:02
    3. 启动线程:start() 4. 线程结束:发出信号finished() 5. 线程退出:quit() (terminate()是直接结束) 6. 等待:wait(); 7. 当前线程ID: QThread::currentThread() 8. 休眠:QThread::msleep(1000); 注意:只有...
  • QT 多线程采用线程池进行网络操作

    千次阅读 2019-05-14 12:05:13
    学习爬取网络数据的工程,但是性能上想达到并发效果,一直做线程,没有做线程池并发效果。 处理中发现: QObject: Cannot create children fora parent that isina different thread. (Parent ...
  • Qt5多线程/线程池技术集锦

    千次阅读 2020-05-13 12:32:51
    Qt有两种多线程的方法,其中一种是继承QThread的run函数,另外一种是把一个继承于QObject的类转移到一个Thread里。 Qt4.8之前都是使用继承QThread的run这种方法,但是Qt4.8之后,Qt官方建议使用第二种方法。 用...
  • Qt线程池,实现多个任务抢占多线程调度功能,用Qt事件循环解决假死
  • 线程池作用就是限制系统中执行线程的数量。 根据系统的环境情况,可以自动或手动设置线程数量,达到运行的最佳效果;少了浪费了系统资源,了造成系统拥挤效率不高。用线程池控制线程数量,其他线程排队等候。一个...
  • 自已用Qt写的线程池实现程序,可以正常运行,用socket进行通讯,很适合初学者学习借鉴;
  • Qt多线程开发之线程池处理QTcpSocket

    千次阅读 2020-08-11 23:19:16
    文章目录Qt多线程开发之线程池处理QTcpSocket重写QTcpServer类MyServer处理QTcpSocket数据类MyClient任务处理对象MyTask Qt多线程开发之线程池处理QTcpSocket QTcpServer等待接收新连接(incomingConnection),当有新...
  • 多线程通信,QT5.11.1,多线程TCP服务器,多线程连接客户端。QThread
  • 我们一般使用该类和QThreadPool来在另一个独立的线程中执行该代码。并且,如果QRunnable对象的autoDelete()设为true的话,QThreadPool会在run()运行结束后自动删除该对象。 重写run函数 protected: void run(); ...
  • qt 多线程实现样例,实现文件的拷贝,亲测可用,重新编译即可
  • Qt中线程已经很早就出现了,关于多线程使用的意义主要是为了减轻主线程的压力,提高用户的体验。 例如:在主线程中需要加载数据库中的很多表格,那么就可以考虑把多表格的读取放到工作线程中去,可以多加载几个...
  • 用opencv调取摄像头选择文件保存路径、可选择是否选取区域录制功能、调取ffmpeg命令行压缩录制视频
  • 1.1、线程池(QThreadPool)管理并重新设置单个QThread对象的样式,以帮助减少使用线程的程序中的线程创建成本。每个Qt应用程序都有一个全局QThreadPool对象,可以通过调用globalInstance()来访问该对象。 1.2、要...
  • 概述 一般的多线程任务大多是避免主线程阻塞(界面卡死),开销线程的次数少。现在有一个光伏监控系统用于采集光伏板的发电功率,每次接收完网络数据包就会进行数据库的写...根据《Qt 多线程编程之敲开 QThread 类的...
  • 初出茅庐之Qt多线程中的线程池QThreadPool和QRunnable 通常情况下,应用程序都是在一个线程中直行操作。但是,当调用一个耗时操作(例如,大批量IO数据或者大量矩阵变换等CPU密集操作)时,用户界面常常会冻结...
  • Qt两种方法实现多线程的开启,及子线程的安全结束线程,及QMutex加锁,Qt单例化实现
  • 基于qt多线程视频采集与传输

    热门讨论 2012-10-08 19:07:54
    将服务端的设备虚拟化,供客户端调用。使用TCP/IP协议传输,使用V4L2实现视频采集。
  • 目录QThreadPool类 主要属性 主要成员函数 ...主要属性:1、activeThreadCount: 此属性表示线程池中的活动线程数,通过activeThreadCount() 调用。 2、expiryTimeout: 线程活着的时间。没有设置expiryTim

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,962
精华内容 784
关键字:

qt线程池多线程使用