开发者

C++ shared memory leak, how to clear shared memory?

开发者 https://www.devze.com 2023-04-13 07:37 出处:网络
I am using Qt and trying to achieve a single instance application by applying this solution in Linux(ubuntu). The problem is that if the application unexpectedly finishes(seg. fault or user kills it)

I am using Qt and trying to achieve a single instance application by applying this solution in Linux(ubuntu). The problem is that if the application unexpectedly finishes(seg. fault or user kills it) the shared memory remains attached and no other process can create it again. Recall from QSharedMemory doc:

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.

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

    // Ensure single instanse of Cevirgec application
    QSharedMemory shared(ApplicationConstants::

    if( !shared.create( 512, QSharedMemory::ReadWrite) )
    {
      // QMessageBox msgBox;
      QMessageBox::critical(0, QObject::t开发者_运维知识库r("application is already running!"), QObject::tr("application is already running!"), QMessageBox::Ok, QMessageBox::Ok);
      qCritical() << "application is already running!";

      exit(0);
    }
    else {
        qDebug() << "application staring...";
    }
    return a.exec(); 
}

What solutions can you suggest here? How can I assure that the shared memory is cleared(or whatever verb used generally) after the process eventually finishes. I need something like finally in java all around the main function :/

EDIT: (Solution)

I have achieved the desired behavior by using QSharedMemory and catching SIGSEGV signal then call sharedMemory.detach() in the signal handler.


You can catch the signals that crash your program and use a handler that calls the QSharedMemory destructor.


Truth is that if your program needs to be killed or has a segfault, then you cannot really do anything about it. Shared memory is not the best choice for ensuring single instance of appliction under UNIX/Linux. Try using semaphores instead, as they are getting closed as soon as your application terminates.

EDIT:

From documentation of sem_close

All open named semaphores are automatically closed on process termination, or upon execve(2).

I also must add that ensuring single-app contraint might have weird consequences on system like linux - imagine somebody logged via ssh with X tunneling and trying to start your app - if somebody is already using it, it will not start. This will be rather confisunig. You are application developer and should know best if you need per-system per-user or even per-X-session blockade.

If you want to use per-user blockade, then solution might be to add hidden file in user home directory containing current pid. Next application will check for this file, and if it exists AND /proc/[pid]/exe link points to current binary, then return error.


You could always run a script after termination of your program to manually clear the shared memory, semaphores, etc. on your system (mine is a Mac Pro running 10.8). I have inserted a script I use for this when running programs that use QSharedMemory, and use it when the program quits unexpectedly and leaves the shared memory instances "hanging".

Keep in mind this will remove all shared memory instances associated with your user name. If you have multiple programs running and using shared memory instances, you should either wait until every program is done, or adjust the script as needed to only delete the shared memory instances that were created by your program.

#!/bin/bash

ME=$(whoami)

IPCS_S=$(ipcs -s | grep $ME | sed "s/  / /g" | cut -f2 -d " ")
IPCS_M=$(ipcs -m | grep $ME | sed "s/  / /g" | cut -f2 -d " ")
IPCS_Q=$(ipcs -q | grep $ME | sed "s/  / /g" | cut -f2 -d " ")

echo "Clearing Semaphores"
for id in $IPCS_S
do
    ipcrm -s $id
done

echo "Clearing Shared Memory"
for id in $IPCS_M 
do
    ipcrm -m $id
done

echo "Clearing Message Queues"
for id in $IPCS_Q
do
    ipcrm -q $id
done
0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号