QT5使用QThread实现工作者线程的总结

2 篇文章 0 订阅

大致翻译于Qt 自带的Help文件,包括范例代码:

实现的方式有两种,第一种是具有全局event loop的功能,可以实时Link 主Dialog或者QWindow的事件,即随时都可以通过connect对应的signal触发线程中的具体功能,线程start一次即可。

//线程,继承于QObject
class Worker : public QObject
  {
      Q_OBJECT

  public slots:
      void doWork(const QString &parameter) {
          QString result;
          /* ... here is the expensive or blocking operation ... */
          //当需要修改界面时,采用Signal链接主界面Class的功能实现。
          emit resultReady(result);
      }

  signals:
      void resultReady(const QString &result);
  };

  class Controller : public QObject
  {
      Q_OBJECT
      //声明一个新线程
      QThread workerThread;
  public:
      Controller() {
          Worker *worker = new Worker;
          //将QObject的所有目标转移至线程内;
          worker->moveToThread(&workerThread);  //很重要
          //连接线程完成信号至清理函数deleteLater
          connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
          //连接主界面工作触发线程信号至工作者线程;
          connect(this, &Controller::operate, worker, &Worker::doWork);
          //连接工作者线程中需要处理主界面的功能至主界面Class下的function;
          connect(worker, &Worker::resultReady, this, &Controller::handleResults);
          //线程启动
          workerThread.start();
      }
      ~Controller() {
          //析构时,先通知线程Event Loop中止;后等待其退出
          workerThread.quit();
          workerThread.wait();
      }
  public slots:
      void handleResults(const QString &);
  signals:
      void operate(const QString &);
  };

第二种是继承于QThread的写法:

//继承于QThread
class WorkerThread : public QThread
  {
      Q_OBJECT
      //重写run函数
      void run() override {
          QString result;
          /* ... here is the expensive or blocking operation ... */
          //当需要修改界面时,采用Signal链接主界面Class的功能实现。
          emit resultReady(result);
      }
      void normalfunction()
       {
        //.......
       }
      QString info;
  signals:
      void resultReady(const QString &s);
  };

  void MyObject::startWorkInAThread()
  {
      WorkerThread *workerThread = new WorkerThread(this);
      //连接线程中需要操作界面的功能至主类QDialog或QWindow的函数
      connect(workerThread, &WorkerThread::resultReady, this,
&MyObject::handleResults);
      //连接退出信号至&QObject::deleteLater
      connect(workerThread, &WorkerThread::finished, workerThread, &QObject::deleteLater);
      workerThread->start();
  }

对于第二种写法,线程启动后,会进入run函数,待run函数执行完后,会自动退出。即不能全局一直通过Connect连接的event触发该线程的功能,而是需要每次都需要start一次该线程。

对于方法二,说明文档中专门说明了其特殊性,其构造函数存活于调用它的线程中,即new 函数存在的主界面触发线程中,而调用的start函数启动的run()函数则存在于启动的新线程中。这种特殊性在于new函数同时构造了class内的所有槽函数以及一般函数。

例如上面的参数QString info, 如果run函数以及normalfunction都有对它的操作,那么这两个操作是存在于两个线程中的。此时就需要调用互斥函数或者QMutexLocker对变量进行处理。

以下是说明文件的原文:

It is important to remember that a QThread instance lives in the old thread that instantiated it, not in the new thread that calls run(). This means that all of QThread's queued slots and invoked methods will execute in the old thread. Thus, a developer who wishes to invoke slots in the new thread must use the worker-object approach; new slots should not be implemented directly into a subclassed QThread.

Unlike queued slots or invoked methods, methods called directly on the QThread object will execute in the thread that calls the method. When subclassing QThread, keep in mind that the constructor executes in the old thread while run() executes in the new thread. If a member variable is accessed from both functions, then the variable is accessed from two different threads. Check that it is safe to do so.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陶醉鱼

感觉写的不错就给个打赏哦

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值