improve terminate fit in musredit qt5/qt6.
Build and Deploy Documentation / build-and-deploy (push) Successful in 22s

This commit is contained in:
2026-09-04 12:41:51 +02:00
parent 32f2d3defa
commit 6222fa5573
4 changed files with 72 additions and 24 deletions
+34 -10
View File
@@ -173,25 +173,49 @@ void PFitOutputHandler::processDone(int exitCode, QProcess::ExitStatus exitStatu
qDebug() << "**ERROR** PFitOutputHandler::processDone: exitCode = " << exitCode << Qt::endl;
#endif
}
fQuitButton->setText("Done");
if (fQuitRequested) {
// the process has now actually terminated in response to quitButtonPressed(); close the dialog
accept();
} else {
fQuitButton->setText("Done");
}
}
//----------------------------------------------------------------------------------------------------
/**
* <p>If the quit button is pressed while the fit is still running, try to terminate musrfit, if this
* does not work, try to kill musrfit.
* <p>If the quit button is pressed while the fit is still running, request musrfit to terminate
* (SIGTERM) and disable the button; a single-shot timer escalates to kill() (SIGKILL) if musrfit
* has not reacted within a few seconds. The dialog is NOT closed here: processDone() (connected to
* QProcess::finished()) calls accept() once the process has actually terminated.
*
* <p>This deliberately never blocks on QProcess::waitForFinished(). A blocking wait here would
* freeze the whole (modal) dialog for up to its default 30 s timeout with no user feedback, which
* in practice led users to force-quit musredit itself while musrfit was still being terminated -
* orphaning the musrfit process, since ~PFitOutputHandler() (the actual terminate/kill/kill-9
* safety net) never got the chance to run.
*/
void PFitOutputHandler::quitButtonPressed()
{
// if the fitting is still taking place, kill it
if (fProc->state() == QProcess::Running) {
fProc->terminate();
if (!fProc->waitForFinished()) {
fProc->kill();
}
if (fProc->state() == QProcess::NotRunning) {
accept();
return;
}
accept();
if (fQuitRequested) // termination already in progress, ignore repeated clicks
return;
fQuitRequested = true;
fQuitButton->setEnabled(false);
fQuitButton->setText(tr("Terminating..."));
fProc->terminate();
// escalate to SIGKILL if musrfit does not react to SIGTERM in time
// (e.g. blocked in slow disk/NFS I/O); accept() happens via processDone()
QTimer::singleShot(5000, this, [this]() {
if (fProc->state() != QProcess::NotRunning)
fProc->kill();
});
}
//----------------------------------------------------------------------------------------------------
@@ -65,6 +65,7 @@ class PFitOutputHandler : public QDialog
private:
Q_PID fProcPID; ///< keeps the process PID
std::unique_ptr<QProcess> fProc; ///< pointer to the musrfit process
bool fQuitRequested = false; ///< set once the user pressed Quit while the process was still running
std::unique_ptr<QVBoxLayout> fVbox; ///< pointer to the dialog layout manager
std::unique_ptr<QPlainTextEdit> fOutput; ///< the captured musrfit output is written (read only) into this text edit object.
+36 -14
View File
@@ -217,7 +217,13 @@ void PFitOutputHandler::processDone(int exitCode, QProcess::ExitStatus exitStatu
if ((exitStatus == QProcess::CrashExit) && (exitCode != 0)) {
qDebug() << "**ERROR** PFitOutputHandler::processDone: exitCode = " << exitCode << Qt::endl;
}
fQuitButton->setText("Done");
if (fQuitRequested) {
// the process has now actually terminated in response to quitButtonPressed(); close the dialog
accept();
} else {
fQuitButton->setText("Done");
}
}
//----------------------------------------------------------------------------------------------------
@@ -226,25 +232,41 @@ void PFitOutputHandler::processDone(int exitCode, QProcess::ExitStatus exitStatu
*
* @details Handles user request to close the dialog. The behavior depends on
* whether the fit is still running:
* - If running: Attempts to terminate musrfit gracefully using QProcess::terminate().
* If graceful termination fails within the timeout period, forcefully kills
* the process using QProcess::kill().
* - If finished: Simply closes the dialog.
* - If running: Requests graceful termination via QProcess::terminate() (SIGTERM)
* and disables the button. A single-shot timer escalates to QProcess::kill()
* (SIGKILL) if musrfit has not reacted within a few seconds. The dialog is
* NOT closed here; processDone() (connected to QProcess::finished()) calls
* accept() once the process has actually terminated.
* - If already finished: Simply closes the dialog.
*
* After ensuring the process is stopped (or was already stopped), accepts the
* dialog (closes it with QDialog::Accepted result).
* @note This slot deliberately never blocks on QProcess::waitForFinished().
* A blocking wait here would freeze the whole (modal) dialog for up to its
* default 30 s timeout with no user feedback, which in practice led users to
* force-quit musredit itself while musrfit was still being terminated -
* orphaning the musrfit process, since ~PFitOutputHandler() (the actual
* terminate/kill/kill-9 safety net) never got the chance to run.
*/
void PFitOutputHandler::quitButtonPressed()
{
// if the fitting is still taking place, kill it
if (fProc->state() == QProcess::Running) {
fProc->terminate();
if (!fProc->waitForFinished()) {
fProc->kill();
}
if (fProc->state() == QProcess::NotRunning) {
accept();
return;
}
accept();
if (fQuitRequested) // termination already in progress, ignore repeated clicks
return;
fQuitRequested = true;
fQuitButton->setEnabled(false);
fQuitButton->setText(tr("Terminating..."));
fProc->terminate();
// escalate to SIGKILL if musrfit does not react to SIGTERM in time
// (e.g. blocked in slow disk/NFS I/O); accept() happens via processDone()
QTimer::singleShot(5000, this, [this]() {
if (fProc->state() != QProcess::NotRunning)
fProc->kill();
});
}
//----------------------------------------------------------------------------------------------------
@@ -132,6 +132,7 @@ class PFitOutputHandler : public QDialog
*/
qint64 fProcPID; ///< Process ID of the running musrfit process.
std::unique_ptr<QProcess> fProc; ///< QProcess object managing the musrfit execution.
bool fQuitRequested = false; ///< Set once the user pressed Quit while the process was still running.
/** @} */
/** @name UI Components