質問

I have a class that is exposed to QML:

qmlRegisterType("SerialThread", 1, 0, "SerialThread");

This class inherits QThread and the QThread.start() is called from QML.

When the user closes the application, how do I properly exit the thread before the program terminates?

役に立ちましたか?

解決

In the destructor, you should call quit() followed by wait(). Since, hopefully, you've made QML own the thread object, it will destruct it - feel free to verify that the destructor is, in fact, executed.

If you don't spin an event loop in the thread, then you must reimplement quit() to set your own stop flag. Since you hide the underlying non-virtual quit(), your "thread" is not really a QThread anymore, and you must inherit from QThread privately - it's a semantic error to do otherwise (and leads to bad bugs).

How such bugs happen? Since you can pass your "not quite" a thread somewhere a QThread is expected, those users of it are free to assume it's a real thread, not a "not quite one", and call QThread::quit() method, which is a no-op without an event loop. Thus bugs.

To maintain LSP, if you need to override non-virtual public methods, you must privately inherit from the parent class, since it's not usable in places where its parent would be usable.

class MyThread : private QThread {
  Q_OBJECT
  Q_DISABLE_COPY(MyThread)
  volatile bool m_stop;
  void run() { ... }
public:
  MyThread(QObject * parent = nullptr) : QThread(parent) { ... }
  void quit() { m_stop = true; }
  // It's important to fully qualify the Priority type, otherwise moc will generate
  // wrong code.
  Q_SLOT void start(QThread::Priority priority = InheritPriority) {
    if (isRunning()) return;
    m_stop = false;
    QThread::start();
  }
  using QThread::isRunning;
  using QThread::isFinished;
  bool isInterruptionRequested() const { return m_stop; }
  ~MyThread() {
    quit();
    wait();
  }
  // Publicly we're only a QObject, not a thread
  operator QObject&() { return *this; }
  operator const QObject&() const { return *this; }
  void run() {
    while (!m_stop) { ... }
  }
};

他のヒント

You can call thread.stop() and check thread.isRunning() before returning exit value in the main.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top