Qt中的多线程(一)

0.前言

Qt中有多种实现多线程的方式,我最常用的有moveToThread()和QtConcurrent::run()两种方式。一般长时间存在的线程我用moveToThread,临时的用QtConcurrent::run(),可惜后者不能使用信号槽。

作为一篇总结,我将列举我了解到的Qt框架中的多线程实现方式。

1.moveToThread()方法配合QThread类

这是Qt官方的推荐实现方式,在QThread的文档中也有其实例代码。

QThread类提供了一个独立于平台的方式来管理线程。一个QThread对象管理程序内的控制的一个线程。线程处理在run()函数中完成。默认情况下,run()通过调用exec()启动事件循环并在线程内运行Qt事件循环。

首先,需要定义一个QObject的子类,实现接口。

#include 
class ProcessObject :public QObject
{
    Q_OBJECT
public:
    explicit ProcessObject(QWidget *parent = nullptr)
        :QObject(parent){}
    ~ProcessObject()
    {}
signals:
    void someSignal();  
public slots:
    void someSlots(){
        //处理
    }
};

接下来就是创建这个QObject子类及一个QThread对象,并使用moveToThread将QObject子类对象转移到子线程中去执行。

#include 
#include "ProcessObject.h" //为上面定义的那个类
class ControlObject : public  QObject
{
    Q_OBJECT   
public:
    explicit ControlObject(QWidget *parent = nullptr)
        :QObject(parent){
        process->moveToThread(processThread);
        //利用信号槽让子线程开始工作
        connect(this,&ControlObject::someSignals,process,&ProcessObject::someSlots);
        //返回处理结果
        connect(process,&ProcessObject::someSignals,this,&ControlObject::someSlots);
        //线程结束时释放对象
        connect(processThread,&QThread::finished,process,&QObject::deleteLater);
        //启动线程
        processThread->start();
    }
    ~ControlObject(){
        processThread->quit();
        processThread->wait();
    }
signals:
    void someSignals();
public slots:
    void someSlots(){
        //处理结果
    }
private:
    QThread *processThread=new QThread(this);
    ProcessObject *process=new ProcessObject;
};

引用一段Qt文档中描述:

当线程started()和finished()时,QThread将通过信号通知您,或者您可以使用isFinished()和isRunning()来查询线程的状态。您可以通过调用exit()或quit()来停止该线程。在极端情况下,您可能希望强制terminate()正在执行的线程。但是,这样做是危险和沮丧的。有关详细信息,请阅读terminate()和setTerminationEnabled()的文档。从Qt 4.8开始,通过将finished()信号连接到QObject :: deleteLater(),可以释放生活在刚刚结束的线程中的对象。使用wait()来阻塞调用线程,直到另一个线程完成执行(或直到指定的时间过去)。QThread还提供静态的,独立于平台的睡眠功能:sleep(),msleep()和usleep()分别允许完整的秒,毫秒和微秒分辨率。这些功能在Qt 5.0中公开。一般来说,wait()和sleep()函数是不必要的,因为Qt是一个事件驱动的框架。而不是wait(),考虑监听finished()信号。而不是sleep()函数,请考虑使用QTimer。

start()有一个线程优先级参数,指示操作系统应如何计划新创建的线程,也可用setPriority()设置。删除QThread对象不会停止执行它管理的线程。删除正在运行的QThread将导致程序崩溃。在删除QThread之前等待finished()信号。

还有就时sleep()系列在windows XP下的精度貌似在15ms,这是系统决定的。

(对于释放move到线程的对象,需要关联线程的finished信号,如果在wait()函数后面直接调用deleteLater()的话该对象的析构函数不能正常执行的,如果直接delete的话容易出现异常,所以,记得关联finished信号)

2.使用QtConcurrent::run()方法

使用 QtConcurrent 模块,需要在 .pro 中添加: QT += concurrent,引用文档描述:

该QtConcurrent命名空间提供高层次的API,使人们可以编写多线程程序,而无需使用低级线程原语,如互斥,读写锁,等待条件或信号。使用QtConcurrent编写的程序会根据可用的处理器核心数自动调整使用的线程数。这意味着今后编写的应用程序将在未来部署在多核系统上时继续扩展。

QtConcurrent::run()可以在另一个线程中运行一个函数:

QFuture QtConcurrent::run(Function function, ...)//参数为函数+参数列表
QFuture QtConcurrent::run(QThreadPool *pool, Function function, ...)//也可指定一个QThreadPool线程池,默认为全局的

#include 
... ...
method(){
    auto myRun=QtConcurrent::run([=](){
        //处理,此处直接用lambda做参数
    });
    myRun.waitForFinished();//一般我只分离没调用wait
}

使用起来很像std::async,要说有什么不方便的话就是不支持信号槽操作

时间问题,暂时写这两个常用的,下次继续。(如有错误,欢迎指正)

你可能感兴趣的:(Qt,略知一二)