繁体   English   中英

如何在同一个程序中崩溃时自动重启Qt应用程序?

[英]How to auto restart a Qt application when it crashes, within the same program?

是否有任何相对“标准”的设计来自动重启Qt应用程序,当它崩溃异常时?

特定于Windows,我是否必须使用任何Windows服务?
或者,如果我必须单独编写另一个程序,那么该怎么做?

以下是使用可以充当监视器或业务逻辑的单个应用程序的方法。 它类似于Jon Harper的答案,除了代码,而不是散文:)

注意

  1. 监视器不应该实例化QApplicationQGuiApplication :它没有UI。 否则,冗余运行过程指示器将出现在某些平台上(即OS X,Win 10)。

  2. 通过在被调用进程中设置环境变量来实现监视/业务逻辑选择。

  3. 通过命令行参数传递监视器/业务逻辑选择是有问题的,因为需要过滤掉命令行开关 - 这样做可以移植而不会遇到极端情况是很棘手的。

  4. 监视进程转发业务逻辑进程的控制台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::invokeQt::QueuedConnection来实现这个Qt::QueuedConnection

     int main(...) { QCoreApplication app; MonitorObject monitor; ... // other initialization code here QMetaObject::invoke(&monitor, "onStarted", Qt::QueuedConnection); return app.exec(); } 

在您的MonitorObject

  • QProcessfinished信号连接到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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM