QThread:线程仍在运行时被销毁?

20

我想在按下按钮 运行 时启动我的 QThread,但编译器输出以下错误:

QThread: Destroyed while thread is still running
ASSERT failure in QThread::setTerminationEnabled(): "Current thread was not started with QThread.", file thread\qthread_win.cp.

我不知道我的代码出了什么问题。

非常感谢任何帮助。

这是我的代码:

SamplingThread::SamplingThread( QObject *parent):
   QwtSamplingThread( parent ),
   d_frequency( 5.0 )
{
   init();
}

MainWindow::MainWindow( QWidget *parent ):
QMainWindow( parent )
{.......
  .....
   run= new QPushButton ("Run",this);
   stop= new QPushButton("Stop",this);
   connect(run, SIGNAL(clicked()),this, SLOT (start()));
}

MainWindow::start
{
   SamplingThread samplingThread;
   samplingThread.setFrequency( frequency() );
   samplingThread.start();
}

int main( int argc, char **argv )
{
   QApplication app( argc, argv );
   MainWindow window;
   window.resize( 700, 400 );
   window.show();
   bool ok = app.exec();
   return ok;
}

SamplingThreadMainWindow::start 的第一行被创建,然后启动,但在 start 返回时仍在运行的情况下立即销毁。错误消息告诉您出了什么问题,而 C++ 语义则告诉您为什么会这样。这个问题与 Qt 没有太多关系,而是与您正在使用的编程语言的语义理解有关。 - Kuba hasn't forgotten Monica
3个回答

37

正如错误信息所述:QThread: Destroyed while thread is still running。您在MainWindow::start方法内创建了SamplingThread对象,但当该方法终止时,该对象超出了范围(即被销毁)。我看到有两种简单的解决方法:

  1. 将您的SamplingThread作为MainWindow的成员,以便其生命周期与MainWindow实例相同。
  2. 您可以使用指针,即使用以下方式创建SamplingThread

    SamplingThread *samplingThread = new SamplingThread;

这有帮助吗?

编辑:为了说明这两种情况,这里简单展示一个粗略的示例。

#include <iostream>
#include <QApplication>
#include <QThread>

class Dummy
{
public:
  Dummy();
  void start();
private:
  QThread a;
};

Dummy::Dummy() :
  a()
{
}


void Dummy::start()
{
  a.start();
  QThread *b = new QThread;
  b->start();

  if( a.isRunning() ) {
    std::cout << "Thread a is running" << std::endl;
  }
  if( b->isRunning() ) {
    std::cout << "Thread b is running" << std::endl;
  }
}

int main(int argc, char** argv)
{
  QApplication app(argc,argv);
  Dummy d;
  d.start();
  return app.exec();
}

1
对于解决方案。2. 你可以基本上采取我写的内容。然后,您必须用“->”替换“.”访问对象,以访问底层对象的方法(如果这对您没有任何意义,我强烈建议您通过一些更多的C++基础教程来学习,例如这里建议的一些:https://dev59.com/_3RC5IYBdhLWcg3wK9yV)。对于1:我不知道你的MainWindow的代码,但通常你声明对象为私有成员类,并在http://en.cppreference.com/w/cpp/language/initializer_list中初始化它。 - Erik
如果你不知道什么是类的成员,那么你应该多了解一些相关知识(例如在这里选择其中一个:http://www.cplusplus.com/doc/tutorial/classes/)。如果你选择第二种方式,你只需要设置频率并在MainWindow::start方法中调用run方法,因为对象已经在初始化列表中被创建了。 - Erik
当然,我知道类的成员是什么或者如何访问方法,实际上,我的评论不是针对你的,我在这个论坛上有另一个问题,并且我想要代码。无论如何,谢谢你提供关于这本书的链接。 - The Man
谢谢,现在它正常运行了。我现在有一个普遍的问题,我以前不习惯像你这样在使用之前初始化我的类的所有成员。这样做是否危险? - The Man
谢谢,这个已经完成了。 - Ahmad Sarabian

5
这是C++的基础知识!你正在堆栈上创建QThread的本地对象,而不是在堆上,因此当你离开MainWindow::start方法时,它会立即被销毁。
应该这样做:
MainWindow::MainWindow( QWidget *parent ):
QMainWindow( parent )
{
   ...

   samplingThread = SamplingThread(this);
   samplingThread->setFrequency( frequency() );

   run= new QPushButton ("Run",this);
   stop= new QPushButton("Stop",this);
   connect(run, SIGNAL(clicked()), samplingThread, SLOT(start()));
}

MainWindow::~MainWindow() {
   samplingThread->waitFor(5000);
}

3

涉及两个不同的 "线程":一个是实际线程,另一个是表示它的 C++ 对象(准确地说,还有另一个线程首先启动此代码)。

错误只是说在销毁表示它的 C++ 对象时,该线程仍在运行。在您的代码中,原因是 QThread 实例局部于 start()。也许您想将 QThread 存储在成员变量中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接