Software
15th October 2015 | By:

How to run a single app instance in QT

Sometimes we don’t want to allow users to run multiple instances of the app at once. We might want to do it, to prevent memory leak, files corruption or we decided there is no practical need to run two instances of our app at once. As there is many ways of completing this task, there is many tricky use cases as well where the single instance lock may fall.

I will show couple of cases how to implement this kind of secure lock and will describe advantages and disadvantages of each method.

Please note each occurrence of `<unique identifier>’ should be replaced by some kind of unique identifier, for example UUID.

1. Using `QLockFile` to create a lock file

This solution is good if we want to check for multiple instances running for each user. The lock file is created in a temporary directory that is specific to a logged in user. This means that each user on the system will be able to run one instance of the app for it’s own.

There is no danger when the app crashes, because the lock will be destroyed with the app instance.

#include <QString>
#include <QLockFile>
#include <QDir>
#include <QMessageBox>

QString tmpDir = QDir::tempPath();
QLockFile lockFile(tmpDir + "/<unique identifier>.lock");

if(!lockFile.tryLock(100)){
    QMessageBox msgBox;
    msgBox.setIcon(QMessageBox::Warning);
    msgBox.setText("You already have this app running."
                    "\r\nOnly one instance is allowed.");
    msgBox.exec();
    return 1;
}

2. Using `QSystemSemaphore` and `QSharedMemory` to create shared memory cluster

As the previous solution is nice and clean, sometimes we want to limit to one instance for the whole machine. It’s impossible to do with the shared lock file as there might be some permission issues. To be sure that our app will run as single instance machine wise we need to use shared memory that is common for all users. This is a bit more complicated solution, as the shared memory is common for all system users we need to be sure only one user can access it at the same time. To ensure that system semaphores are coming with help. By using system semaphores we can ensure the given part of code and shared memory will be used by single instance at the same time.

QSystemSemaphore sema("<unique identifier>", 1);
    sema.acquire();

#ifndef Q_OS_WIN32
    // on linux/unix shared memory is not freed upon crash
    // so if there is any trash from previous instance, clean it
    QSharedMemory nix_fix_shmem("<unique identifier 2>");
    if(nix_fix_shmem.attach()){
        nix_fix_shmem.detach();
    }
#endif

    QSharedMemory shmem("<unique identifier 2>");
    bool is_running;
    if (shmem.attach()){
        is_running = true;
    }else{
        shmem.create(1);
        is_running = false;
    }
    sema.release();

    if(is_running){
        QMessageBox msgBox;
        msgBox.setIcon(QMessageBox::Warning);
        msgBox.setText("You already have this app running."
                        "\r\nOnly one instance is allowed.");
        msgBox.exec();
        return 1;
    }

There are many more ways of ensuring single instance run on the machine, however I find these the most agile, simple and universal.

Tags: , , ,

3 Comments

  1. Martin
    6th December 2016 @ 13:23

    I was thinking abandon using the method #2 as the QSharedMemory is not clear uppong a crash. But your solution was really interesting. I did some test and to get it work properly you have to add this line

    // Prevent multiple application instances
    QSystemSemaphore sema(“Sonar-Key”, 1);
    sema.acquire();

    #if !defined(Q_OS_WIN32)
    // On linux/unix shared memory is not freed upon crash
    // so if there is any trash from previous instance, clean it
    QSharedMemory nix_fix_shmem(“Sonar-Key2”);
    bool bDetach = false;
    if (nix_fix_shmem.attach() == false)
    {

    bDetach = nix_fix_shmem.detach();
    }

    nix_fix_shmem.detach();
    #endif

    QSharedMemory shmem(“Sonar-Key2”);
    bool is_running;
    if (shmem.attach() == true)
    {

    is_running = true;
    }

    else
    {

    shmem.create(1);
    is_running = false;
    }

    sema.release();

    Reply
    • Martin
      6th December 2016 @ 13:25

      sory, i did not mention the line :

      #if !defined(Q_OS_WIN32)
      // On linux/unix shared memory is not freed upon crash
      // so if there is any trash from previous instance, clean it
      QSharedMemory nix_fix_shmem(“Sonar-Key2”);
      bool bDetach = false;
      if (nix_fix_shmem.attach() == false)
      {
      bDetach = nix_fix_shmem.detach();
      }
      nix_fix_shmem.detach(); // <——– This one
      #endif

      Reply
  2. Hojjat
    25th January 2017 @ 11:48

    Hi,
    I don’t know what version of Qt you used but QSharedMemory::lock() is a semaphore itself and the QSystemSemaphore is not required.

    Thanks.

    Reply

Leave a reply

Your email address will not be published. Not now, not ever. Required fields are marked *

Comments


You may use these HTML tags and attributes:

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Name
Email
Website