购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

1.2 多线程的创建和管理

Qt通过3种形式提供对线程的支持,分别是平台无关的线程类、线程安全的事件投递、跨线程的信号槽连接。

Qt中主要的线程类如下。

● QThread:提供跨平台的多线程解决方案。

● QThreadStorage:提供逐线程数据存储。

● QMutex:提供相互排斥的锁或互斥量。

● QMutexLocker:辅助类,可自动对 QMutex 加锁与解锁。

● QReadWriteLock:提供可以同时读写操作的锁。

● QReadLocker与QWriteLocker:自动对QReadWriteLock 加锁与解锁。

● QSemaphore:提供整型信号量,是互斥量的泛化。

● QWaitCondition:线程在被其他线程唤醒之前一直休眠。

QThread是Qt线程中的一个公共的抽象类,所有的线程类都是从QThread抽象类中派生的。需要实现QThread中的虚函数run,可通过start函数来调用run函数。在默认情况下,QThread::run会启动一个事件循环(QEventLoop::exec)。线程相关的函数如下。

● void run:线程体函数,用于定义线程的功能。

● void start:启动函数,用于将线程入口地址设置为run函数。

● void terminate:用于强制结束线程,不保证数据完整性和资源释放。

QCoreApplication::exec总是在主线程(执行main的线程)中被调用,不能从一个QThread中调用。在图形用户界面(GUI)程序中,主线程也称为GUI线程,是唯一允许执行GUI相关操作的线程。另外,必须在创建一个QThread前创建QApplication(或QCoreApplication)对象。

当线程启动和结束时,QThread会发送信号started和finished,可以使用isFinished和isRunning来查询线程的状态。

通过静态函数currentThreadId和currentThread返回当前正在执行的线程的标识,前者返回线程的ID,后者返回一个线程指针。

如果要设置线程的名称,可以在启动线程之前调用setObjectName。如果不调用setObjectName函数,那么线程的名称将是线程对象的运行时类型(QThread子类的类名)。

在新的线程中使用QThread类执行代码可通过以下几种方式。

1.继承QThread类

重写QThread的void run函数,在重写的函数中添加需要执行的代码。在以下代码中,NewThread类通过继承QThread类,重写run函数,实现一个新的线程。

  #include <QThread>
 
  class NewThread : public QThread
  {
  public:
      explicit NewThread(QObject *parent = 0);
  protected:
      void run()
  {
      // 具体语句      
  }

2.使用 QThread::create

使用 QThread::create(要求Qt版本至少为Qt 5.10)直接创建一个QThread对象,它可接收一个函数类型的参数,当调用QThread::start时会在新的线程中执行此函数。以下代码为使用QThread::create函数的示例。

  void function()
  {
      //具体语句
  }
  
  QThread *new_thread = QThread::create(function);
  new_thread->start();

3.直接创建一个QThread对象

直接创建一个QThread对象,将一个QObject对象移动到此线程,则使用QMetaObject :: invokeMethod调用此对象的槽函数就会在新的线程中执行。以下代码为使用moveToThread的示例。

  class Object : public QObject
  {
      Q_OBJECT
  public:
      explicit Object(QObject *parent = nullptr);
  
  public slots:
      void function() {
          //具体语句
      }
  };
  
  QThread *new_thread = new QThread();
  Object *object = new Object();
  object->moveToThread(new_thread);//将对象交给线程
  new_thread->start();
  QMetaObject::invokeMethod(object, "function");

QRunnable类可以和QThreadPool(线程池)配合使用。和QThread的第一种使用方法类似,开发者也需要通过继承并重写QRunnable::run函数,从而在新的线程中执行代码。以下代码为使用QRunnable的示例。

  class Runnable : public QRunnable
  {
  public:
      void run() override
      {
          //具体语句
      }
  };
  QRunnable *runnable = new Runnable();
  runnable->setAutoDelete(runnable);
  QThreadPool::globalInstance()->start(runnable);

QtConcurrent类是基于QRunnable封装的上层接口,可以很方便地在一个新的线程中执行一个函数,也可以和QThreadPool配合使用,以满足更灵活的功能需求。以下代码为使用QtConcurrent的示例。 NNfu6U0Rb7CLwjhEGea+j7TqoQm0eQSdtZ71GvYOWUtr8zuwHCoAXK72pZV+2Q7h

  void function()
  {
      //具体语句
  }
  QtConcurrent::run(function);
点击中间区域
呼出菜单
上一章
目录
下一章
×