Qt多线程使用方法总结

Qt有两种开启多线程的方法,一种是继承QThread,然后重写run函数,另一种是把一个继承于QObject的类调用movetothread方法转移到一个Thread中。这两种方法都经常使用,这里记录一下需要注意的事项。

一,继承QThread得到MyThread

MyThread只有run函数是运行在子线程中的,其它所有的函数运行在创建MyThread时的线程中。

通俗来说就是如果你是在主线程中创建的MyThread,那么MyThread的其它函数就都运行在主线程中。所以,如果MyThread中有耗时的操作都要写在run函数中,否则会卡住主界面。因此如果MyThread中有某个变量既会被run函数使用,也会被其他函数使用,那么就要加锁,因为这涉及到跨线程的操作。

使用线程就会涉及到线程如何安全退出的问题。在这里什么时候线程会退出了?就是run函数运行结束的时候。如果你的run函数中没有死循环,那么当run函数运行结束,线程就自然退出了。如果有死循环了?显然调用线程的exit和quit是不起作用的,因为QThread并没有主动的调用exec()实现消息循环。那么最简单的方法就是添加一个bool变量,在主线程中通过修改这个bool变量的值来主动退出循环,结束run函数。

创建线程时也有一个问题需要注意,假设我们这么写 m_thread = new MyThread(this),这里的this指的是窗体的指针,意思就是创建线程时把窗体的指针作为父对象。那么我们不能手动delete m_thread。Qt会帮我们处理,但是我们要保证m_thread能够正常退出,也就是说在窗体的析构函数中先结束m_thread中的run函数(如果run中有死循环的话),然后调用m_thread->wait(),这些都要写在析构函数中delete ui前面。还有种创建线程的方式  m_thread = new MyThread,就是new线程时不指定父对象,那么通过绑定QThread::finished信号和QObject::deleteLater槽也可以安全的退出线程(当然如果run函数中有死循环的话要先退出循环)。

 

二,继承QObject得到MyThread

MyThread的槽函数是运行在子线程中的,其它所有的函数运行在创建MyThread时的线程中。

QObject来实现多线程有个非常好的优点,就是默认就支持事件循环。继承QThread要支持事件循环需要在QThread::run()中调用QThread::exec()来提供对消息循环的支持,因此如果要使用信号和槽,那就直接使用QObject来实现多线程。QObject的线程转移函数是:void moveToThread(QThread * targetThread) ,通过此函数可以把一个顶层Object(就是没有父级)转移到一个新的线程里。

Qt的官方例子大概如下:


class Worker : public QObject
{
   Q_OBJECT
   ........
   ........
   //把需要在子线程中进行的操作都声明为槽函数
};


class Controller : public QObject
{
   Q_OBJECT

   QThread workerThread;//普通的线程
public:
   Controller() 
   {
      Worker *worker = new Worker;
      worker->moveToThread(&workerThread);
      //线程结束,自己退出
      connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);

      //这里去connect的线程的槽函数
      //..............
      //..............

      workerThread.start();
   }

   ~Controller() 
   {
       workerThread.quit();
       workerThread.wait();
   }

};

使用QObject创建多线程的方法如下:

  1. 写一个继承QObject的类,对需要进行复杂耗时逻辑的入口函数声明为槽函数
  2. 此类在旧线程new出来,不能给它设置任何父对象
  3. 同时声明一个QThread对象,在官方例子里,QThread并没有new出来,这样在析构时就需要调用QThread::wait(),如果是堆分配的话, 可以通过deleteLater来让线程自杀
  4. 把obj通过moveToThread方法转移到新线程中,此时object已经是在线程中了
  5. 把线程的finished信号和object的deleteLater槽连接,这个信号槽必须连接,否则会内存泄漏
  6. 正常连接其他信号和槽(在连接信号槽之前调用moveToThread,不需要处理connect的第五个参数,否则就显示声明用Qt::QueuedConnection来连接)
  7. 初始化完后调用'QThread::start()'来启动线程
  8. 在逻辑结束后,调用QThread::quit退出线程的事件循环

本文主要参考博主YBAdiam的博客,原文链接如下:https://blog.csdn.net/Aidam_Bo/article/details/81746246

 

你可能感兴趣的:(Qt)