【问题标题】:How to manage single instance of a Qt app on crash?如何在崩溃时管理 Qt 应用程序的单个实例?
【发布时间】:2015-02-18 09:34:02
【问题描述】:

我想将我的应用程序作为单个实例执行,目前我正在使用QSharedMemory 并且工作正常。我在 Ubuntu 12.04 上使用 Qt5.2.1。

下面是我的测试代码:

QApplication a(argc, argv);
a.processEvents();

const char* MEM_KEY = "56";
QSharedMemory sharedMem(MEM_KEY);

if( !sharedMem.create( 512, QSharedMemory::ReadWrite) )
{
  QMessageBox msgBox;
  msgBox.setText( QObject::tr("Can't start more than one instance of the application.") );
  msgBox.setIcon( QMessageBox::Critical );
  msgBox.exec();
  exit(0);
}


MainWindow w;
w.show();

int p=0;
//p=p/0; // create exception here

return a.exec();

但是if 使应用程序崩溃(如上面的代码所示)。如果我再次启动应用程序,它会显示Can't start more than one instance of the application,这意味着即使之前的实例已经崩溃,它仍然存在。在我的情况下不应该发生这种情况。

在这种情况下如何重新启动我的应用程序?

编辑:

实际上我的原始项目包含很多源文件(上面的一个只是为了测试而制作的)。我想在我的原始项目中通过编辑最少的源文件来实现它,如果可能的话,只能通过编辑 main.cpp

【问题讨论】:

  • 如果你尝试/catch你崩溃了会发生什么,在catch中解锁共享内存然后退出应用程序?
  • 好的,有可能,但在我的情况下,我的原始项目包含许多源文件(上面只是为了测试而制作的),我想通过编辑最少的源文件在我的原始项目中实现它,如果可能的话,只能通过编辑 main.cpp
  • QSharedMemory::error()sharedMem.create 失败后返回什么? 题外话 - 你可以使用静态函数 QMessageBox::critical(...) 而不是你使用的 4 行
  • 感谢您的建议,QSharedMemory::error() 在崩溃和实例存在时返回 4(之前的应用程序正常运行)。
  • 我通过使用解决方案 [这里][1] [1] 得到了它的工作:stackoverflow.com/questions/5006547/…

标签: c++ qt


【解决方案1】:

您可以使用 QSetting:

int main(int argc, char *argv[])
{
    QSettings settings;
    QApplication a(argc, argv);

    if(!settings.exitedNormaly()) {
        // In case of crash
    }

    // set the flag to false
    settings.setExitedNormaly(false);

    MainWindow w(&settings);
    w.processArg(argc, argv);
    w.show();

    int result = a.exec();
    settings.setExitedNormaly(result == 0);

    return result;
}

结合您的共享内存,您将能够在应用程序崩溃的情况下解锁该块。

【讨论】:

  • 嗨,假设应用程序正在运行并且用户再次启动应用程序,那么我该如何使用上述解决方案,意味着 setExitedNormaly 仍然为假。
  • @Haris 我真的不知道...也许有第二个设置存储打开实例的数量?
【解决方案2】:

对于 Linux:

//------------------------------------------------

QProcess *m_prSystemCall;
m_prSystemCall = new QProcess();

QString Commnd = "pgrep  " + qApp->applicationDisplayName();
m_prSystemCall->start(Commnd);
m_prSystemCall->waitForFinished(8000);
QString output(m_prSystemCall->readAllStandardOutput());
QStringList AppList = output.split("\n", QString::SkipEmptyParts);
qDebug() <<"pgrep out:"<<AppList;
for(int i=0;i<AppList.size()-1;i++)
{
    Commnd = "kill " + AppList.at(i);
    m_prSystemCall->start(Commnd);
    m_prSystemCall->waitForFinished(8000);
}

//--------------------------------------------- ----------

对于 Windows:

#include <tlhelp32.h>
#include <comdef.h>

QString pName = qApp->applicationDisplayName();
pName += ".exe";
PROCESSENTRY32 entry;
entry.dwSize = sizeof(PROCESSENTRY32);

HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, NULL);

if (Process32First(snapshot, &entry) == TRUE)
{
    DWORD myPID =  GetCurrentProcessId();
    while (Process32Next(snapshot, &entry) == TRUE)
    {
        const WCHAR* wc = entry.szExeFile ;
        _bstr_t b(wc);
        const char* c = b;

        if (stricmp(c, pName.toStdString().c_str()) == 0)
        {
            HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, entry.th32ProcessID);

            qDebug() <<"myPID: "<< myPID << "entry.th32ProcessID" << entry.th32ProcessID;
            if(myPID != entry.th32ProcessID)
                TerminateProcess(hProcess,0);
            QThread::msleep(10);
            CloseHandle(hProcess);
        }
    }

}

CloseHandle(snapshot);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-01
    • 1970-01-01
    • 2014-02-20
    相关资源
    最近更新 更多