Qt多线程

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/a34140974/article/details/81911376

1 开启线程
QThread类提供了一个平台无关的方式来管理线程。 实际上由于Qt信号槽机制的原因,本人觉得Qt的多线程对新手而言存在很多坑。
Qt中关于线程的类为QThread。只要继承该类,并实现run()方法就可以在主线程中方便的启动新线程,启动函数为QThread.start()。然而,自定义的run()内并没有自动实现Qt的消息循环(当然它也不应该有),因此即便在新线程内连接了信号和槽,新线程也不能处理。如下:

class ElsClient:public QThread
{
    Q_OBJECT
public:
    explicit ElsClient(QThread *parent = nullptr);
protected:
    void run(){
        connect(..)//DirectConnection 无效
        // do some thing
}
signals:
public slots:
    void myFunc();
};

除非在覆写的run()的末尾加上exec()函数。这里有一个问题,run()方法内不能存在死循环,要不然exec()根本不会执行到。此方法的另一个问题在于,例子中的ElsClient一般会在主线程中实例化(假设为elsClient),因此该实例(包括内部的所有变量)都是属于主要线程的 ,此时不能connect elsClient的非指针成员变量,否则出错。以此得出结论,线程的槽不应直接在QThread子类中来实现。
使用Qt线程的还有另一个方式。在QThread类内部的run()方法默认是调用了exec()的,因此可以直接新建QThread的实例,并调用其start()方法运行线程。如下:

QThread workerThread;
Worker *worker = new Worker;//实际工作类
worker->moveToThread(&workerThread);
connect(workerThread, SIGNAL(..), worker, SLOT(..));
workerThread.start();

此时,如果信号发出,SLOT函数将工作在子线程。
感觉QThread不像是被设计成一个线程的基类,倒像是一个线程的管理类。但那个子线程开启/结束的时候会发出started()和finished()信号。用户也可以是isFinished()和isRunning查询线程状态。
exit()/quit()可以用来终止线程。如果要线程强行停止,也可使用terminate().
从Qt4.8起,可以释放运行刚刚结束的线程对象,通过连接finished()信号到QObject::deleteLater().
使用wait()来阻塞调用的线程,直到其他线程执行完毕(或者直到指定的时间过去)。
QThread中还提供了静态的、平台独立的休眠功能:sleep()、msleep()、usleep()允许秒,毫秒和微秒来区分,这些函数在Qt5.0中被设为public。
静态函数currentThreadId()和currentThread()返回标识当前正在执行的线程。前者返回该线程的平台特定的ID,后者返回一个线程指针。
2 结束线程
如果一个线程运行完成,就会结束。可很多情况并非这么简单,由于某种特殊原因,当线程还未执行完时,我们就想中止它。
不恰当的中止往往会引起一些未知错误。比如:当关闭主界面的时候,很有可能次线程正在运行,这时,就会出现如下提示:

QThread: Destroyed while thread is still running

这是因为子线程还在运行,就结束了UI主线程,导致事件循环结束。这个问题在使用线程的过程中经常遇到,尤其是耗时操作。
大多数情况下,当程序退出时,子线程也许会正常退出。但是在极少数的情况下会出现crash!一种方法是使用terminate()函数结束子线程,但是很多情况下某些销毁工作必须得执行,此时terminate()就比较尴尬了。
比较优雅的方式有:
1. 发起线程退出操作,调用quit()或exit()。
2. 等待线程完全停止,删除创建在堆上的对象。
3. 适当的使用wait()(用于等待线程的退出)和合理的算法。
即便如此,有时候当Qt程序被关闭时,也会出现如下错误信息。

QBasicTimer::stop: Failed. Possibly trying to stop from a different thread

Stack Overflow上有评论说这个是Qt的一个bug,并不会造成任何问题(事实如何,有待进一步查阅资料)。

展开阅读全文

没有更多推荐了,返回首页