QThread官方帮助文档-详细介绍部分(个人翻译)

程序中,一个QThread对象能管理控制一个线程。线程启动于run()。默认下,调用exec()后,run()才在线程中开启一个Qt事件循环。
用QObject::moveToThread()将工作对象移动到指定线程。

  class Worker : public QObject
  {
      Q_OBJECT

  public slots:
      void doWork(const QString &parameter) {
          QString result;
          /* ... here is the expensive or blocking operation ... */
          emit resultReady(result);
      }

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

  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(this, &Controller::operate, worker, &Worker::doWork);
          connect(worker, &Worker::resultReady, this, &Controller::handleResults);
          workerThread.start();
      }
      ~Controller() {
          workerThread.quit();
          workerThread.wait();
      }
  public slots:
      void handleResults(const QString &);
  signals:
      void operate(const QString &);
  };

Worker槽函数代码将在单独的线程中执行。你可随意地将Worker的槽函数连接至任何线程内任何对象的任何信号。得益于queued connections机制,不同线程间的信号槽连接是安全的。

让代码运行在独立线程的另一种办法是,继承QThread,重新实现run()。例如:
  class WorkerThread : public QThread
  {
      Q_OBJECT
      void run() override {
          QString result;
          /* ... here is the expensive or blocking operation ... */
          emit resultReady(result);
      }
  signals:
      void resultReady(const QString &s);
  };

  void MyObject::startWorkInAThread()
  {
      WorkerThread *workerThread = new WorkerThread(this);
      connect(workerThread, &WorkerThread::resultReady, this, &MyObject::handleResults);
      connect(workerThread, &WorkerThread::finished, workerThread, &QObject::deleteLater);
      workerThread->start();
  }

本例中,run函数返回后,单独线程将退出。除非调用exec(),否则线程内没有任何事件循环。非常重要的一点,QThread实例存活在初始化他的旧线程中,并不在调用run()的新线程中。也就是说,
QThread的队列槽和唤醒方法都是在旧线程中执行的。因此,若开发者想在新线程中召唤槽函数,必须用工作对象worker-object模式,且切勿在在QThread子类中实现新的槽函数。
不同与队列槽函数(或唤醒方法),QThread对象直接调用的方法将在调用该方法的线程上执行。当继承QThread时,切记,构造于旧线程,run()执行与新线程。当两个函数都访问同一成员变量时,变量是
被两个线程访问的。一定验证该变量安全后,再去做其他操作。

管理线程
当线程启动和停止时,QThread通过信号通知你;isFinished()和isRunning()用于查询线程状态。exit()和quit()用来停止线程。紧急情况下,用terminate()可强行终止线程。这样操作比较危险,一般情
况,不建议这么干。详见terminate()和setTerminationEnabled()帮助文档。

从Qt4.8开始,通过连接finished()信号和QObject::deleteLater(),线程结束后,线程内的对象可释放了。
wait()用于阻塞调用线程,直到其他线程完成执行(或指定的时间到了,即超时)。

Qt5.0中,QThread开始提供静态的、平台无关的休眠函数:sleep()、msleep()和usleep(),分别用于解决秒、毫秒和微秒的休眠。


注意:
Qt是基于事件驱动的框架,故通常情况下,wait()和sleep()是不需要的。用等待finished()信号代替wait()。用QTimer代替代替sleep()。
静态函数currentThreadld()和currentThread()返回正在执行线程的ID。前者返回平台特定的线程ID。后者返回一个QThread指针。


类似linux下,用ps -L命令定义名称一样,为了线程名称可被选中,开启线程前,使用setObjectName()设置其名称。如果你不调用setObjectName(),线程的名称就是该线程对象运行时的类名称。例如,
在Mandelbat例子中的RenderThread,就是QThread子类的名称。注意,Windows下的发布版本本操作不可行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值