Qt扫盲-QThread使用总结

QThread理论使用总结

  • 一、概述
  • 二、使用方式
    • 1. 方式一
    • 2. 方式二
  • 三、线程管理
    • 1. 线程状态及信息
    • 2. 线程退出
    • 3. 线程休眠

一、概述

一个 QThread 管理程序中的一个线程。QThreads在run()中开始执行。默认情况下,run() 通过调用 exec() 来启动事件循环,并在线程中运行Qt事件循环。 在这个 QThread 属于Qt 线程支持的低级API,同时 QThread 是跨平台的,因为 QThread 封装的是 本地的 线程库,就像 Windows 下是 win32 thread, 或者Linux下的 pthread。同时它们可以与相同本机API的线程一起使用。QThread是Qt中所有线程控制的基础,每个QThread实例代表并控制一个线程。

QThread可以直接实例化,也可以子类化。有两个使用方法

  • 实例化一个 QThread 提供了一个并行事件循环环境,在环境里可以在第二个线程中调用QObject槽函数。
  • 子类化一个QThread可以让应用程序在开始它的事件循环之前初始化一个新的线程,或者在没有事件循环的情况下运行并行代码。

也就是下面的两个方式

二、使用方式

下面的例子就是使用QObject::moveToThread()将worker对象移动到线程中。Worker槽函数中的代码会在一个单独的线程中执行。

我们可以自由地将Worker的槽连接到任何线程中的任何对象的任何信号。由于一种称为排队连接(queued connections)的机制,在不同的线程之间连接信号和槽是安全的。

1. 方式一

//在线程中待执行的代码
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 &)}

2. 方式二

另一种让代码在单独的线程中运行的方法是子类化QThread并重新实现run()。例如:

//重载 QThread 实现自己的线程功能
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的排队槽和调用的方法将在旧线程中执行。因此,希望在新线程中调用任务槽的开发人员必须使用工作对象方法;新槽函数不应该直接实现到子类QThread中。

与队列中的任务槽或被调用的方法不同,直接在QThread对象上调用的方法将在调用该方法的线程中执行。当子类化QThread时,记住构造函数在旧线程中执行,而run()在新线程中执行。如果在两个函数中都访问成员变量,那么访问该变量的是两个不同的线程。检查这样做是否安全。

三、线程管理

1. 线程状态及信息

当线程 started() 和 finished() 时 ,QThread将通过信号通知您,或者您可以使用 isFinished() 和 isRunning() 来查询线程的状态。

线程的优先级可以通过 priority() 来获取,也可以通过 setPriority() 来设置执行的优先级,一般不会经常使用的。

静态函数 currentThreadId() 和 currentThread() 返回当前执行线程的标识符。前者为线程返回平台特定的ID;后者返回一个QThread指针。

要选择为线程指定的名称(例如,在Linux上由命令ps -L标识),可以在启动线程之前调用 setObjectName() 。如果不调用setObjectName(),给线程的名称将是线程对象的运行时类型的类名。

请注意,目前在Windows上的release版本中不可用。

2. 线程退出

可以调用 exit() 或 quit() 来停止线程。在极端情况下,你可能想要 强制终止 terminate() 一个正在执行的线程。但有一些注意事项

terminate() 终止线程的执行。线程可以立即终止,也可以不立即终止,这取决于操作系统的调度策略。在terminate()之后使用QThread::wait()来确定。
当线程终止时,所有等待线程结束的线程将被唤醒。

Qt官方说:此函数是危险的,不鼓励使用。线程可以在其代码路径的任何位置终止。线程可以在修改数据时终止。线程没有机会进行自我清理,解锁任何持有的互斥量等。简而言之,仅在绝对必要时使用该函数。
可以通过调用QThread::setTerminationEnabled()显式启用或禁用终止。当终止被禁用时调用这个函数会导致延迟终止,直到终止被重新启用。

QThread::setTerminationEnabled() 的解释是 根据enabled参数启用或禁用当前线程的终止。线程必须是由QThread启动的。当enabled为false时,禁用终止。将来对QThread::terminate()的调用将立即返回,而不会产生任何影响。相反,终止被推迟到启用终止。
当enabled为true时,启用终止。以后对QThread::terminate()的调用将正常地终止线程。如果终止被延迟(即QThread::terminate()被禁用终止调用),此函数将立即终止调用线程。注意,这个函数在这种情况下不会返回。

从Qt 4.8开始,通过将 finished() 信号连接到 QObject::deleteLater(),可以释放生活在刚刚结束的线程中的对象。

3. 线程休眠

QThread 可以使用 wait() 来阻塞正在调用的线程,直到另一个线程完成执行(或超过指定的时间)。

QThread还提供了静态的、平台无关的休眠函数:sleep()、msleep()和usleep()分别允许完整的秒级、毫秒级和微秒级分辨率。这些函数在Qt 5.0中是公开的。
注意:一般来说,wait()和sleep()函数应该是不必要的,因为Qt是一个事件驱动框架。考虑监听finished()信号,而不是wait()。考虑使用QTimer代替sleep()函数。

你可能感兴趣的:(#,▶,Qt扫盲,QThread,QThread理论,QThread使用,Qt的QThread使用,qt5)