5

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::tr("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.

Community
  • 1
  • 1
destan
  • 4,301
  • 3
  • 35
  • 62
  • You probably shouldn't be trying to make an app that behaves differently from how the OS and users expect Apps to behave. If standard behavior for the OS is such that users expect to be able to launch multiple instances, as on Windows and Linux, then they should just be able to. If the standard behavior is to force a single instance, as on Macs, then let the OS enforce that itself. – bames53 Oct 14 '11 at 20:46
  • 2
    well there is no standard for such behaviors in OSes. It is totally application dependent – destan Oct 14 '11 at 20:51
  • bames53: there are tons of apps that only let you start one instance, and sometimes it's the logical thing to do. – rubenvb Oct 14 '11 at 20:55
  • @destan Well at least some OSes do, and working contrary to the consistant behavior set out by the OS is the wrong thing to do. On the other hand if the OS's user environment doesn't have any standards and apps just have a hodge podge of different behaviors then go for it, do whatever you want. – bames53 Oct 14 '11 at 21:13
  • @rubenvb Yeah, personally that's the behavior I like in applications I use. But the user environments for some OSes set standards contrary to my personal preferences, presumably because they're catering to users with different preferences. – bames53 Oct 14 '11 at 21:16

3 Answers3

6

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

bames53
  • 86,085
  • 15
  • 179
  • 244
  • Yes, e.g. for an object f of class Foo: `f.~Foo();`. But you must only do so in circumstances where the language will not also call the destructor automatically. – bames53 Oct 14 '11 at 21:09
  • Yes, you can - but I don't know if it you can depend on anything qt-related in signal handler, as such handlers should be self contained and not relay on anything else in program. – j_kubik Oct 14 '11 at 21:11
  • C++11 says "When the processing of the abstract machine is interrupted by receipt of a signal, the values of objects which are neither 1.) of type `volatile std::sig_atomic_t` nor 2.) lock-free atomic objects (29.4) , are unspecified during the execution of the signal handler, and the value of any object not in either of these two categories that is modified by the handler becomes undefined." I don't know if `QSharedMemory` conforms to these requirements. Perhaps you want `QtSingleApplication` suggested by the top voted answer in that other question you linked. – bames53 Oct 14 '11 at 21:44
  • 1
    unfortunately `QtSingleApplication` is no longer maintained and now kind of deprecated – destan Oct 14 '11 at 22:04
1

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
rvijay007
  • 1,357
  • 12
  • 20
1

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.

j_kubik
  • 6,062
  • 1
  • 23
  • 42
  • but there the same problem arises, if crashed semaphore remains acquired – destan Oct 14 '11 at 22:24
  • I have achieved the desired behavior by combining QSharedMemory and catching SIGSEGV signal then call sharedMemory.detach() But in your edit you remind me that in multi user system there will be a problem if 2 or more users try to run the app. Well it is an gui dependent app and nobody would run it via ssh even with -X param but they may want to run it on the same machine in the same time anyways. Thanks for pointing that – destan Oct 14 '11 at 23:32