停止Qt线程:调用exit()或quit()不会停止线程执行 [英] Stop Qt Thread : calling exit() or quit() does not stop the thread execution

查看:58
本文介绍了停止Qt线程:调用exit()或quit()不会停止线程执行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在main()即主线程中创建了一个QThread.将工作程序类移至新线程.该线程执行工作程序类的"StartThread"方法.

Created a QThread in main() i.e Main thread. Moved a worker class to the new thread. The thread executes the 'StartThread' method of worker class.

工作线程:

//header file
class Worker : public QObject
{
    Q_OBJECT
public:
    Worker(QThread* thread);

public slots:
    void StartThread(); 
    void EndThread();

private:
    QThread* m_pCurrentThread;
};


// source file
#include "QDebug"
#include "QThread"
#include "worker.h"

Worker::Worker(QThread* thread)
{
m_pCurrentThread = thread;
}

void Worker::StartThread()
{
    qDebug() << " StartThread";

    while(true)
    {
        QThread::msleep(1000);
        qDebug() << " thread running";
        static int count = 0;
        count++;
        if(count == 10)
        {            
            break;
        }
        if(m_pCurrentThread->isInterruptionRequested())
        {
            qDebug() << " is interrupt requested";
            // Option 3:  
            m_pCurrentThread->exit();               
        }
    }
    qDebug() << "StartThread finished";
}

void Worker::EndThread()
{
    qDebug() << "thread finished";
}

Main.cpp

#include <QCoreApplication>
#include "worker.h"
#include "QThread"
#include "QObject"
#include "QDebug"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QThread* thread = new QThread();
    Worker* workerObj = new Worker(thread);

    QObject::connect(thread,
                     SIGNAL(started()),
                     workerObj,
                     SLOT(StartThread()));
    QObject::connect(thread,
                     SIGNAL(finished()),
                     workerObj,
                     SLOT(EndThread()));



    workerObj->moveToThread(thread);
    thread->start();
    thread->requestInterruption();
    QThread::msleep(2000);
    qDebug() << "terminate thread";
    if(thread->isRunning())
    {   
        // Option 1,2 exit() / quit() used but got same output
        thread->exit(); 
        qDebug() << "wait on  thread";
        thread->wait();
    }
    qDebug() << " exiting main";

    return a.exec();
}

现在,在"StartThread"完成且线程退出之前,我想从Main线程停止线程.已使用

Now before the 'StartThread' completes and thread is exited gracefully I want to stop the thread from Main thread. Used,

  1. 线程-> exit()并在主线程中等待(thread-> wait()).
  2. 线程-> quit()并在主线程中等待(thread-> wait()).

  1. thread->exit() and waited (thread->wait()) in the Main thread.
  2. thread->quit() and waited (thread->wait()) in the Main thread.

exit()在"StartThread"中

exit() in the 'StartThread'

预期:从主线程调用exit()/quit()后,线程执行应立即停止.

Expected: The thread execution should stop as soon as exit()/quit() is called from Main thread.

实际:在所有三个实例中,线程均保持运行,完成"StartThread"方法并正常退出.最好不调用exit()/quit().输出:

Actual: In all three instances the thread keeps running, completes the 'StartThread' method and exits gracefully. As good as not exit()/quit() was called. output:

StartThread
 thread running
 is interrupt requested
terminate thread
wait on  thread
 thread running
 is interrupt requested
 thread running
 is interrupt requested
 thread running
 is interrupt requested
 thread running
 is interrupt requested
 thread running
 is interrupt requested
 thread running
 is interrupt requested
 thread running
 is interrupt requested
 thread running
 is interrupt requested
 thread running
StartThread finished
thread finished
exiting main

是否可以在主线程需要时停止/处置线程?

推荐答案

isInterruptionRequested 仅在调用 QThread :: requestInterruption 时返回true,不返回 QThread :: quit .这是有据可查的.

isInterruptionRequested only returns true if you've called QThread::requestInterruption, not QThread::quit. This is documented.

如果要使用 QThread :: quit ,则该线程必须旋转事件循环,因此您不应从该事件循环派生.而是这样做:

If you want to use QThread::quit, the thread must spin an event loop, so you shouldn't be deriving from it; instead do this:

class Worker : public QObject {
  QBasicTimer m_timer;
  int chunksToDo = 20;
  void doChunkOfWork() {
    QThread::sleep(1);
  }
  void timerEvent(QTimerEvent * ev) {
    if (ev->timerId() != m_timer.timerId()) return;
    if (!chunksToDo) { m_timer.stop(); return; }
    doChunkOfWork();
    if (!--chunksToDo) emit done();
  }
public:
  explicit Worker(QObject * parent = nullptr) : QObject{parent} {
    m_timer.start(0, this);
  }
  Q_SIGNAL void done();
};

要运行工作程序,请创建它并将其移至其线程中的某个位置.要停止工作程序,只需在工作程序完成之前 quit()其线程即可.

To run the worker, create it and move it to some its thread. To stop the worker, just quit() its thread before the worker is done.

int main(int argc, char ** argv) {
  QCoreApplication app{argc, argv};
  Worker worker;
  QThread thread;
  worker.moveToThread(&thread);
  QObject::connect(&worker, &Worker::done, &thread, &QThread::quit);
  QObject::connect(&thread, &QThread::finished, &app, &QCoreApplication::quit);
  thread.start();
  return app.exec();
}

您可能希望使用线程池代替手动管理线程的寿命.

Instead of managing the thread's life manually, you might wish to use a thread pool instead.

class Worker : public QObject, QRunnable {
  int chunksToDo = 20;
  volatile bool active = true;
  void doChunkOfWork() {
    QThread::sleep(1);
  }
  void run() {
    while (active && chunksToDo) {
      doChunkOfWork();
      --chunksToDo;
    }
    emit done();
  }
public:
  using QObject::QObject;
  Q_SLOT void stop() { active = false; }
  Q_SIGNAL void done();
};

int main(int argc, char ** argv) {
  QCoreApplication app{argc, argv};
  QThreadPool pool;
  Worker worker;
  worker.setAutoDelete(false); // important!
  pool.start(&worker);
  // *
  QTimer::singleShot(5000, &worker, &Worker::stop);
  QObject::connect(&worker, &Worker::done, &app, &QCoreApplication::quit);
  return app.exec();
}

在不运行主事件循环的情况下结束它的另一种方法是:

An alternate way to end it without running the main event loop would have been:

  // *
  QThread::sleep(5);
  worker.stop();
  pool.waitForDone();
}

此答案具有将多个作业流式传输到线程池的完整示例.

This answer has a complete example of streaming multiple jobs to a thread pool.

这篇关于停止Qt线程:调用exit()或quit()不会停止线程执行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆