Qt:单实例应用程序保护的最佳实践

Jas*_*enX 39 c++ qt qmutex qsharedmemory

QSingleApplicationQMutexQSharedMemory?我正在寻找能在Windows,OSX和Linux(Ubuntu)中顺利运行的东西.使用Qt 4.7.1

Dmi*_*nov 66

简单的解决方案,做你想要的.没有网络依赖(as QtSingleApplication),没有任何开销.

用法:

int main()
{
    RunGuard guard( "some_random_key" );
    if ( !guard.tryToRun() )
        return 0;

    QAppplication a(/*...*/);
    // ...
}
Run Code Online (Sandbox Code Playgroud)

RunGuard.h

#ifndef RUNGUARD_H
#define RUNGUARD_H

#include <QObject>
#include <QSharedMemory>
#include <QSystemSemaphore>


class RunGuard
{

public:
    RunGuard( const QString& key );
    ~RunGuard();

    bool isAnotherRunning();
    bool tryToRun();
    void release();

private:
    const QString key;
    const QString memLockKey;
    const QString sharedmemKey;

    QSharedMemory sharedMem;
    QSystemSemaphore memLock;

    Q_DISABLE_COPY( RunGuard )
};


#endif // RUNGUARD_H
Run Code Online (Sandbox Code Playgroud)

RunGuard.cpp

#include "RunGuard.h"

#include <QCryptographicHash>


namespace
{

QString generateKeyHash( const QString& key, const QString& salt )
{
    QByteArray data;

    data.append( key.toUtf8() );
    data.append( salt.toUtf8() );
    data = QCryptographicHash::hash( data, QCryptographicHash::Sha1 ).toHex();

    return data;
}

}


RunGuard::RunGuard( const QString& key )
    : key( key )
    , memLockKey( generateKeyHash( key, "_memLockKey" ) )
    , sharedmemKey( generateKeyHash( key, "_sharedmemKey" ) )
    , sharedMem( sharedmemKey )
    , memLock( memLockKey, 1 )
{
    memLock.acquire();
    {
        QSharedMemory fix( sharedmemKey );    // Fix for *nix: http://habrahabr.ru/post/173281/
        fix.attach();
    }
    memLock.release();
}

RunGuard::~RunGuard()
{
    release();
}

bool RunGuard::isAnotherRunning()
{
    if ( sharedMem.isAttached() )
        return false;

    memLock.acquire();
    const bool isRunning = sharedMem.attach();
    if ( isRunning )
        sharedMem.detach();
    memLock.release();

    return isRunning;
}

bool RunGuard::tryToRun()
{
    if ( isAnotherRunning() )   // Extra check
        return false;

    memLock.acquire();
    const bool result = sharedMem.create( sizeof( quint64 ) );
    memLock.release();
    if ( !result )
    {
        release();
        return false;
    }

    return true;
}

void RunGuard::release()
{
    memLock.acquire();
    if ( sharedMem.isAttached() )
        sharedMem.detach();
    memLock.release();
}
Run Code Online (Sandbox Code Playgroud)

  • @AoeAoe它是一个代码示例,没有任何限制.即使没有任何评论,也可以随意使用它. (6认同)
  • 这对我有用,如果应用程序崩溃,它将允许重启(这是我的问题),谢谢@SaZ (3认同)
  • @SaZ感谢您发布此代码 - 我只是在我的应用程序中尝试过它 - 它第一次工作:) (3认同)
  • 另一个问题:你不能只使用 `QSharedMemory::lock()` 而不是单独的 `QSystemSemaphore` 吗? (3认同)
  • 哇.工作得很完美!非常感谢:)只需要在main中包含RunGuard.h. (2认同)
  • 这是一个很棒的实现!非常感谢,正是我需要的! (2认同)

Ita*_*dev 6

由于QtSingleApplication相对过时且不再维护,因此我编写了一个替代文件,称为SingleApplication

它基于QSharedMemory并使用QLocalServer来通知父进程正在生成的新实例。它适用于所有平台,并与Qt 5兼容。

完整的代码和文档可在此处获得


Nej*_*jat 2

您可以使用QSharedMemory特定的密钥并检查是否可以创建具有该密钥的共享内存。如果它也无法创建它,则实例已经运行:

QSharedMemory sharedMemory;
sharedMemory.setKey("MyApplicationKey");

if (!sharedMemory.create(1))
{
    QMessageBox::warning(this, tr("Warning!"), tr("An instance of this application is running!") );

    exit(0); // Exit already a process running
}
Run Code Online (Sandbox Code Playgroud)

  • 解决方案并不完整。有很多可能的故障。当应用程序崩溃时,您不会检查案例。您可以查看我的回答完整解决方案。 (7认同)
  • 这个解决方案确实非常不完整。-1 (4认同)