QThread对象作为辅助类的成员

QThread object as a member of worker class

本文关键字:成员 对象 QThread      更新时间:2023-10-16

我读过很多关于为什么在大多数情况下子类化QThread是个坏主意的文章,以及如何正确使用QThread,调用moveToThread方法。在这里我们可以看到这样一个设计的典型例子。

我正在设计的课程应该满足以下要求:

  • 它想要使用信号和插槽,所以我需要一个事件循环,并将使用moveToThread

  • 它将只显示带有信号和插槽的接口。没有普通的C++方法。

  • 所有槽都应该在对象的专用线程中执行,每个对象一个线程。因此,线程应该在创建对象时创建,并且应该在对象死亡时完成。

因此,脑海中浮现出一个显而易见的解决方案(未经测试,只是一个草图代码):

class Worker : public QObject {
Q_OBJECT
public:
    Worker() {
        thread = new QThread();
        // ...Some signal-slot connections may be done here...
        // ...Some other connections may be performed by user code...
        moveToThread(thread);
        thread->start();
    }
    ~Worker() {
        thread->exit();
        thread->wait();
        delete thread;
    }
public slots:
    void process(); // and other interface slots
signals:
    // Interface signals
private:
    QThread* thread;
};

因此,重点是将QThread对象声明为worker类的(私有)成员,但我从未在任何示例或其他人的代码中见过这种情况。

这就是为什么我怀疑这个设计是否有缺陷?它有一些我没有注意到的致命缺点吗?还是可以,只是不经常需要?

只要将对象移出工作线程,这是可能的。以下是您可以做到的方法——请注意,您应该按值保存线程,而不是不使用编译器为您管理内存。

class Worker : public QObject {
  Q_OBJECT
  QThread m_thread;
public:
  Worker() {
    m_thread.start();
    moveToThread(&m_thread);
  }
  ~Worker() {
    // Move us out of any thread.
    // moveToThread must always be called from QObject::thread()!
    {
      QObject sig;
      sig.connect(&sig, &QObject::destroyed, this, [this]{
        this->moveToThread(0); // become thread-less
        m_thread->quit();
      });
    }
    // Wait for the thread to stop
    m_thread.wait();
  }
};

假设工作可以通过QtConcurrent::run异步完成,那么很可能无论如何都不应该使用这样的对象。最有可能的是,您将浪费大部分空闲的线程,因为您不太可能始终保持线程可运行。不可运行的线程本质上是一种浪费的资源。