3

I am implementing an application using Qt C++ where I have used QSharedMemory to restrict multiple instances of the application. Relevant code segment in main.cpp is as follows,

QSharedMemory sharedMemory;
sharedMemory.setKey(SM_INSTANCE_KEY);

if (!sharedMemory.create(1))
{
    QMessageBox::warning(0, "Console", "An instance of this application is already running!" );
    exit(0); /* Exit, already a process is running */
}

On opening the Application, I can see that a shared memory has been created for my application. (shmid 7045192, size 1B)

enter image description here

So far so good. Problem arises when my application crashes for some reason. On crashing, the sharedMemory is not getting cleared, so I can't open the application anymore. When it crashes, attached application count becomes 0, but the shared memory does not get deleted. Relevant screen-shot is as follows

enter image description here

As per as my understanding, as the status of the shared memory is not marked as dest like other shared memories, it is not getting deleted even when there is not any attached process.

So, my question is that is there any way of marking status of the Shared Memory as dest ?

Surajeet Bharati
  • 1,363
  • 1
  • 18
  • 36

1 Answers1

12

Quoting QSharedMemory documentation:

When using this class, be aware of the following platform differences:

Windows: QSharedMemory does not "own" the shared memory segment. When all threads or processes that have an instance of QSharedMemory attached to a particular shared memory segment have either destroyed their instance of QSharedMemory or exited, the Windows kernel releases the shared memory segment automatically.

Unix: QSharedMemory "owns" the shared memory segment. When the last thread or process that has an instance of QSharedMemory attached to a particular shared memory segment detaches from the segment by destroying its instance of QSharedMemory, the Unix kernel release the shared memory segment. But if that last thread or process crashes without running the QSharedMemory destructor, the shared memory segment survives the crash.

HP-UX: Only one attach to a shared memory segment is allowed per process. This means that QSharedMemory should not be used across multiple threads in the same process in HP-UX.

I've add the same issue on Linux few years ago, we solved the problem by doing those steps:

// Pseudo code
if (create_share_memory() == failed)
{
    // The failure may be caused by the shm already existing
    attach()
    detach() // This should delete the shm if no process use it
    if (create_share_memory() == failed)
    {
       // We really cannot create the share memory, report the error
       return failed
    }
}
return ok
Benjamin T
  • 8,120
  • 20
  • 37
  • You can also : 1- Init shm 2- attach / detach 3- Check here if you can create . This way it's more readable and you don't have x2 'if'. But thanks, this fix saved my day!! – svalsesia Aug 28 '17 at 14:07
  • 1
    @user2629409 It simplifies the code but at the cost of reduce performance if you do not expect the shared memory to exist. That is if the case where the shared memory already exist is exceptional (e.g. caused by a crash), you have 2 extra system calls in the normal cases (the app didn't crash or you are on a platform that automatically destroys dangling shm: 99.9%). For some software where you need performance you might want to skip the extra system calls. However if you expect that you will need to attach/detach most of the time, then yes you should remove the first if. – Benjamin T Aug 28 '17 at 17:50
  • @Benjamin T On Linux I need to do this trick every time. I use shared memory to prevent multiple execution of the same app. at the same time. So for me it's extra code just for Windows and OSX one time, at startup :) – svalsesia Aug 29 '17 at 19:58
  • @user2629409 If so, you might be interested by QtSingleApplication: https://github.com/qtproject/qt-solutions/tree/master/qtsingleapplication – Benjamin T Aug 29 '17 at 21:42