Qt QThread在运行时立即失败

时间:2014-03-26 01:21:57

标签: c++ multithreading qt qthread

Qt Thread在运行时立即失败,这是我的标题:

class Stepper1_run : public QThread
{
public:
    void system_run();
private:
    void run();
};

这是.cpp代码:

void Stepper1_run::run(){
    //do whatever
}


void Stepper1_run::system_run()
{
   Stepper1_run stepper1_run;
   stepper1_run.start();
}

当从gui点击按钮时调用它:

void MainWindow::on_button_run_clicked()
{
    Stepper1_run stepper1_run;
    stepper1_run.system_run();
}

最初,system_run()函数本身就是一个函数,我被告知它需要成为该类的成员,否则该线程将立即关闭。不幸的是,该函数仍然在运行时立即关闭并出现错误:`QThread:在线程仍在运行时被销毁"程序退出。

是什么导致这种情况发生?

2 个答案:

答案 0 :(得分:2)

您已在堆栈中声明了您的线程对象,此处:

void MainWindow::on_button_run_clicked()
{
    Stepper1_run stepper1_run;  // <- Stepper1_run is instantiated
    stepper1_run.system_run();  // <- Thread starts
}  // <- stepper1_run goes out of scope and is destroyed.

一旦超出范围,对象就会被销毁,这会在您调用system_run()后立即发生,因此会出错。

使其成为集体成员是一种选择。你可以把它变成一个指针(或者一个Qt自动指针);如果您一次只能运行此线程的一个实例,这是合适的。要启动线程,请实例化Stepper1_run,启动它并存储指针。要停止线程,请指示它停止,加入它,然后删除实例并重置指针。在销毁包含类时,请务必在销毁之前停止线程(您可以执行常规停止 - &gt; join - &gt;删除包含类析构函数中的逻辑)。

更新;评论中要求的示例:

class MainWindow : ... {
    ...
public:
    ~MainWindow ();
public slots:
    void startSystem ();
    void stopSystem ();
private:
    QScopedPointer<Stepper1_run> stepper_;
};

MainWindow::~MainWindow () {
    stopSystem(); // <- proper termination of thread on exit
}

void MainWindow::startSystem () {
    stopSystem();
    stepper_.reset(new Stepper1_run());
    stepper_->system_run();
}

void MainWindow::stopSystem () {
    if (stepper_) { 
        stepper_->whateverStopsTheThread(); // <- you'd need to implement this
        stepper_->wait(); // <- i.e. join; waits for thread to terminate
        stepper_.reset(); // <- i.e. delete
    }
}

该示例是众多可能性中的一种,您的场景可能会有所不同。为简洁起见,也省略了错误处理/异常安全(具体细节也取决于您的情况)。上面的例子假设只是一个线程应该运行,并且启动一个新线程应该终止旧线程。

顺便说一句,请注意,使用slots,您只需connect()按钮的clicked()信号即可startSystem()。这也为您提供了从其他线程调用startSystem()stopSystem()的方法,让Qt处理同步细节。

如果您打算将指针传递给其他对象(它与QSharedPointer的API略有不同,请使用QScopedPointer,请阅读文档)。如果你想出于某种原因使用C风格的指针,它类似于上述情况中的QScopedPointer,只需记住在NULL构造函数中将其初始化为MainWindow做。

答案 1 :(得分:-2)

只需在标题上声明stepper1_run就像这样。

class Stepper1_run : public QThread
      {
      public:
      void system_run();
      private:
     void run();
     Stepper1_run stepper1_run;
      };


    void MainWindow::on_button_run_clicked()
    {
     stepper1_run.system_run();
    }