[英]How to auto restart a Qt application when it crashes, within the same program?
是否有任何相對“標准”的設計來自動重啟Qt應用程序,當它崩潰異常時?
特定於Windows,我是否必須使用任何Windows服務?
或者,如果我必須單獨編寫另一個程序,那么該怎么做?
以下是使用可以充當監視器或業務邏輯的單個應用程序的方法。 它類似於Jon Harper的答案,除了代碼,而不是散文:)
監視器不應該實例化QApplication
和QGuiApplication
:它沒有UI。 否則,冗余運行過程指示器將出現在某些平台上(即OS X,Win 10)。
通過在被調用進程中設置環境變量來實現監視/業務邏輯選擇。
通過命令行參數傳遞監視器/業務邏輯選擇是有問題的,因為需要過濾掉命令行開關 - 這樣做可以移植而不會遇到極端情況是很棘手的。
監視進程轉發業務邏輯進程的控制台I / O以及返回代碼。
// https://github.com/KubaO/stackoverflown/tree/master/questions/appmonitor-37524491
#include <QtWidgets>
#include <cstdlib>
#if defined(Q_OS_WIN32)
#include <windows.h>
#else
static void DebugBreak() { abort(); }
#endif
static int businessLogicMain(int &argc, char **argv) {
QApplication app{argc, argv};
qDebug() << __FUNCTION__ << app.arguments();
QWidget w;
QHBoxLayout layout{&w};
QPushButton crash{"Crash"}; // purposefully crash for testing
QPushButton quit{"Quit"}; // graceful exit, which doesn't need restart
layout.addWidget(&crash);
layout.addWidget(&quit);
w.show();
QObject::connect(&crash, &QPushButton::clicked, DebugBreak);
QObject::connect(&quit, &QPushButton::clicked, &QCoreApplication::quit);
return app.exec();
}
static char const kRunLogic[] = "run__business__logic";
static char const kRunLogicValue[] = "run__business__logic";
#if defined(Q_OS_WIN32)
static QString getWindowsCommandLineArguments() {
const wchar_t *args = GetCommandLine();
bool oddBackslash = false, quoted = false, whitespace = false;
// skip the executable name according to Windows command line parsing rules
while (auto c = *args) {
if (c == L'\\')
oddBackslash ^= 1;
else if (c == L'"')
quoted ^= !oddBackslash;
else if (c == L' ' || c == L'\t')
whitespace = !quoted;
else if (whitespace)
break;
else
oddBackslash = false;
args++;
}
return QString::fromRawData(reinterpret_cast<const QChar*>(args), lstrlen(args));
}
#endif
static int monitorMain(int &argc, char **argv) {
#if !defined(Q_OS_WIN32)
QStringList args;
args.reserve(argc-1);
for (int i = 1; i < argc; ++i)
args << QString::fromLocal8Bit(argv[i]);
#endif
QCoreApplication app{argc, argv};
QProcess proc;
auto onFinished = [&](int retcode, QProcess::ExitStatus status) {
qDebug() << status;
if (status == QProcess::CrashExit)
proc.start(); // restart the app if the app crashed
else
app.exit(retcode); // no restart required
};
QObject::connect(&proc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), onFinished);
auto env = QProcessEnvironment::systemEnvironment();
env.insert(kRunLogic, kRunLogicValue);
proc.setProgram(app.applicationFilePath()); // logic and monitor are the same executable
#if defined(Q_OS_WIN32)
SetErrorMode(SEM_NOGPFAULTERRORBOX); // disable Windows error reporting
proc.setNativeArguments(getWindowsCommandLineArguments()); // pass command line arguments natively
env.insert("QT_LOGGING_TO_CONSOLE", "1"); // ensure that the debug output gets passed along
#else
proc.setArguments(args);
#endif
proc.setProcessEnvironment(env);
proc.setProcessChannelMode(QProcess::ForwardedChannels);
proc.start();
return app.exec();
}
int main(int argc, char **argv) {
if (qgetenv(kRunLogic) != kRunLogicValue)
return monitorMain(argc, argv);
else
return qunsetenv(kRunLogic), businessLogicMain(argc, argv);
}
如果應用程序崩潰,那就完成了。
您的監視器想法很好,可以使用QProcess
實現。 使用“monitor”來引導您的實際應用程序。 為此,請使用QProcess
成員實現監視對象。 在偽代碼中:
class MonitorObject : public QObject
{
...
public Q_SLOTS:
void onStarted();
void onFinished(int, QProcess::ExitStatus);
...
private:
QProcess m_process;
}
然后在main
:
QCoreApplication
和監視對象。 將排隊的信號發送到監視器對象,以便它知道主事件循環何時開始。 你可以使用QMetaObject::invoke
和Qt::QueuedConnection
來實現這個Qt::QueuedConnection
:
int main(...) { QCoreApplication app; MonitorObject monitor; ... // other initialization code here QMetaObject::invoke(&monitor, "onStarted", Qt::QueuedConnection); return app.exec(); }
在您的MonitorObject
:
QProcess
的finished
信號連接到onFinished
。 MonitorObject::onStarted
,啟動該進程。 QProcess::finished
信號觸發時,重新啟動有問題的程序或退出,具體取決於發出信號中的exitCode
參數。 我不知道在崩潰時重啟應用程序的任何標准Qt方法。 但是有一個很好的課程,這使得編寫監督/監督課程變得非常容易。 它被稱為QProcess。
你可以像這樣開始這個過程:
monitorClass::startProcess(QString commandLine) // e.g. "c:\mytestapp.exe param1 param2"
{
mp_Process = new QProcess(this);
mp_Process->start(commandLine);
mp_Process->waitForStarted();
// Start a timer
mp_Timer->start(1000);
}
然后當計時器到期時(每秒 - 或其他)
void monitorClass::TimerExpired(void)
{
switch (mp_Process->state())
{
default:
case QProcess::NotRunning:
{
qDebug("Process has stopped un-expectedly\n");
// Tell the supervisor that the process has terminated
// restart the process
startProcess("c:\mytestapp.exe param1 param2"); // just an example
break;
}
case QProcess::Starting:
case QProcess::Running:
{
qDebug("Process is running ok\n");
break;
}
}
}
注意
這實際上是偽代碼,它不是一個可編譯的例子 - 它只是向您展示使用QProcess執行此操作的難易程度...
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.