QT建立一个线程来处理耗时的工作

作者:fly 发布于:2017-2-17 13:12 分类:Linux


1、建立一个工作类,派生于QObject,比如:Worker,用于执行耗时操作:

class Worker : public QObject
{
    Q_OBJECT
public slots:
    // 长时间的作业
    void doWork()
    {
        // ...
        emit progress("正在...");
        // ...
        // 通知当前线程退出,即投递一个退出事件
        QThread::currentThread()->quit();
    }
    // ...
signals:
    void progress(const QString &text); // 进度
    // ...
};



2、建立一个QThread的子类,用于启动线程和消息循环:

class Launcher : public QThread
{
    Q_OBJECT
protected:
    void run()
    {
        exec(); // 执行事件循环
    }
public:
    void launchWorker(Worker *worker)
    {
        // 初始化worker
        // ...
        worker->moveToThread(this); // 把worker移动到当前线程
        start(); // 启动线程
    }
};




3、使用这2个类:

Launcher launcher;
Worker *worker = new Worker;
connect(worker, SIGNAL(progress(QString)), mainWindow, SLOT(updateProgress(QString)), Qt::QueuedConnection);
launcher.launchWorker(worker);
QMetaObject::invokeMethod(worker, "doWork", Qt::QueuedConnection);
launcher.wait();
delete worker;



注意,worker的progress signal和主窗口mainWindow(GUI线程某个响应的类)的updateProgess slot是通过QueuedConnection类型来连接的。因为当前在doWork里触发progress的时候,mainWindow可能还在响应事件(如窗口事件)或做其它事情。不要用DirectConnection类型来连接,避免出现未知的行为。

QMetaObject::invokeMethod调用doWork,这时也是用的QueuedConnection类型,即通过事件循环来执行doWork。

一个QObject对象属于创建它的线程,它能处理这个线程给他分配的事件。

注意worker和launcher都是属于GUI线程的,所以launchWorker里面把worker移动到了launcher线程,只有这样worker才能接收launcher线程里的事件。

请参考:

http://qt-project.org/doc/qt-4.8/thread-basics.html

http://qt-project.org/wiki/Threads_Events_QObjects





发表评论:

 
Powered by emlog sitemap