2

プラットフォーム:Win7 x64、MinGW-rubenvb(4.7.2-x64)、Qt 4.8

次のように、QConcurrent :: runを使用して生成された長いタスク(ポピュレーションファイルの読み取り、ポピュレーションファイルの書き込み、シミュレーションの実行)がほとんどないとします。

void MainWindow::runLengthyJob() {
    /* some setup */
    jobWatcher->setFuture(QConcurrent::run(theApp, &AppClass::lengthyJob));
    // lengthyJob - can be readPop(), writePop(), runSim()
}

通常、これらのタスクは完了するまでに少なくとも15秒かかります(シミュレーションの場合、数時間以上かかります)。まだ完了していないスレッドによるクラッシュを防ぐために、MainWindow::closeEventを次のように再実装します。

void MainWindow::closeEvent(QCloseEvent *event) {
    /* wait for any dangling thread */
    if (QThreadPool::globalInstance()->activeThreadCount())
        QThreadPool::globalInstance()->waitForDone();
    event->accept();
} // end: MainWindow::closeEvent

これは問題なく動作しますが、MainWindowの「x」ボタンをクリックすると、アプリが最終的に終了したにもかかわらず、フリーズして「応答していません」(テキストはOSから提供されていると思います)と表示されているようです。

MainWindowのclose()スロットがトリガーされたらすぐにアプリを終了したい。では、まだ完成していないスレッドの待機時間を短縮するにはどうすればよいでしょうか。または、実行中の長いジョブがまだあることをユーザーに通知するにはどうすればよいですか(完全にシャットダウンするまでに数時間かかる場合があります)。(closeEventにQDialog / QMessageboxを含めようとしましたが、新しく作成されたウィジェットもフリーズします)

注:AppClass:lengthyJobs [readPop()/ writePop()]の場合、これらは自己完結型の関数であり、小さなステップに分解することはできません。AppClass :: runSim()の場合、より小さなステップが可能になる場合があります。

4

1 に答える 1

0

まず第一に、QtConcurrent::runによって返されるfutureはキャンセルをサポートしていません。したがって、キャンセルすることはできません。最善の方法は、AppClassにフラグを設定し、longyJobsでそれをチェックして(runSimの場合は可能であると述べたように)、完了するのを待つことです。

いずれにせよ、実行中のタスクをユーザーに通知する場合は、次の操作を実行できます。QDialogのサブクラスを作成し、QTimerを使用してWaitDialogを作成し、ダイアログの作成時にこのタイマーを開始し、timeout()信号をこのスロットに接続します。ダイアログを開き、実行中のスレッドがない場合はダイアログを受け入れます。

if (QThreadPool::globalInstance()->activeThreadCount() == 0)
    accept();

次に、MainWindow :: closeEvent:

void MainWindow::closeEvent(QCloseEvent *event) {
    WaitDialog dlg;
    dlg.exec();
    event->accept();
}
于 2013-03-13T05:47:58.590 に答える