停止 QRunnable 导致主窗口无法关闭

Posted

技术标签:

【中文标题】停止 QRunnable 导致主窗口无法关闭【英文标题】:Stopped QRunnable cause Mainwindow un-closable 【发布时间】:2013-05-01 14:41:43 【问题描述】: 平台:Qt 4.8.2(使用 MinGW x64 从源代码构建),Win 7

我正在使用 QRunnable 将长时间运行的任务与主 GUI 线程分开,我有时会遇到随机崩溃/奇怪的行为,而没有可追溯的错误。请帮助提供有关调试内容/方式的建议。谢谢

Runner 类:信号/槽连接到主窗口的多继承

class MyRunner : public QObject, public  QRunnable

    Q_OBJECT
Q_SIGNALS:
    void feedbackLog(QString text);
    void finished();
public:
    explicit MyRunner(/* some args */)  /* some initialization */ 

    void run() 
        stopped_ = false;
        for (int run = 0; run < SOME_COUNT; run++) 

            Q_EMIT feedbackLog("Resetting everything ...");
            if (stopped_) return;

            /* start the daily interaction until the epidemic is over */
            do
            
                if (stopped_) return;
                lengthySubTaskA();
                if (stopped_) return;
                lengthySubTaskB();
                if (stopped_) return;
                lengthySubTaskC();
            
            while (conditionNotReached());
         // end: for(run)
        stopped_ = true;
        Q_EMIT finished();
    
    bool isStopped()  return stopped_; 
public Q_SLOTS:
    void stop() 
        Q_EMIT feedbackLog("Cancel ...");
        stopped_ = true;
    
private:
    bool stopped_;
    /** other class members follow */
;

主窗口段

void MainWindow::callMyRunnable() 
    runner_ = new MyRunner(/* args */); // runner_ is class member */
    runner_->setAutoDelete(true); // (a)
    progress_dialog_ = new QProgressDialog("Running", "Cancel", 0, 0, this);
    progress_dialog_->setAttribute(Qt::WA_DeleteOnClose);

    connect(runner_, SIGNAL(feedbackLog(QString)), SLOT(logMessage(QString)));
    connect(runner_, SIGNAL(finished()),           SLOT(endLengthyJob()));
    connect(runner_, SIGNAL(finished()), progress_dialog_, SLOT(close()));
    connect(progress_dialog_, SIGNAL(canceled()), runner_, SLOT(stop()));
    connect(progress_dialog_, SIGNAL(canceled()), SLOT(endLengthyJob()));

    QThreadPool::globalInstance()->start(runner_);
    progress_dialog_->show();
    /* flu_runner_->deleteLater(); */ // (b)


void MainWindow::closeEvent(QCloseEvent *e) 
     if (runner_ && !runner_->isStopped()) runner_->stop(); // (c)
     if (QThreadPool::globalInstance()->activeThreadCount())
     
         /* display a dialog to notify user about shutdown */
         Dialog::WaitDialog dlg(5 * 1000);
         dlg.exec();
     
     event->accept();
 // end_event(MainWindow::closeEvent)

1) 如果我在 (a) 处禁用自动删除,我应该添加语句 (b) 以防止泄漏吗?或者有什么更好的方法来处理泄漏?

2) 有时,当 Runnable 任务完成时,我无法正常关闭应用程序([x] 按钮和 Alt-F4 都不起作用),我必须从 QtCreator 中终止应用程序(我正在调试,对吗? )。这可能是什么原因?

[Edit]: 3) 对于不可关闭的主窗口,有时会在我取消MyRunner类处理的任务后发生,这可能是原因吗?

[编辑]:我在(c)周围添加了qDebug()语句,发现它在(c)处停止并拒绝继续显示等待对话框,以防[x]按钮没有响应。

谢谢。

【问题讨论】:

为什么 runner_ 和 progress_dialog_ 是班级成员 - 您是否在其他任何地方访问它们?它们应该是程序逻辑的局部变量,因为每个 callMyRunnable() 都会有效地重置这些指针。如果您需要从其他任何地方访问它们,这可能是问题的根源,否则,我建议将它们设为本地以确保这些指针不会在 callMyRunnable() 之外使用 对于 runner_,如果用户通过 [x] 按钮关闭主窗口,我需要停止生成的线程,请检查我的关闭事件并查看我帖子中的语句 (c)。如果我只使用 QThreadPool::waitForDone(),runner_ 运行的任务可能需要几个小时才能停止,这将冻结我的应用程序。 对于progress_dialog_,我不能使用模态对话框,因为我希望用户在主窗口上交互一些小部件。如果我将 dialog.show() 与局部变量一起使用,它会很快消失,让用户没有机会取消任务。 好的,但是如果你输入 callMyRunnable() 两次,第一个 runner 将无法访问。如果你需要访问它——你需要一些指针容器来存储它们——比如 std::vector,而不是 MyRunner*. 如果有单个进度对话框/运行器 - 在构造函数中创建它并在析构函数中删除它,只能在 callMyRunnable() 中访问它们。如果您需要多个跑步者/对话框 - 您将需要一些容器。 【参考方案1】:

通过更改主窗口的“关闭策略”来解决问题:删除“自动杀死”并强制用户等待产生的线程。变量 runner_progress_dialog_ 现在本地化为函数 callMyRunnable()

【讨论】:

以上是关于停止 QRunnable 导致主窗口无法关闭的主要内容,如果未能解决你的问题,请参考以下文章

重用 QRunnable

无法停止导入数据

WINDOWS 服务主进程已停止工作?

如何关闭 WPF 中隐藏的主窗口?

如何杀死 PyQt5 中的 QRunnable?

关闭模态视图控制器会导致音乐停止