10

I want to make sure that users can't run more than one instance of my application. My pseudo code looks like this:

sem_t one_instance_only=sem_open(UNIQUE_NAME,O_CREAT | O_EXCL,...);
if(SEM_FAILED==one_instance_only)
{
    if(E_EXIST==errno)
    {
    // application already running
    exit(1);
    }
}
sem_close(...);
//without the call to sem_unlink() the semaphore still lingering even if app not 
// running
sem_unlink(...);     

I tried it and it works, but I just want to make sure that I am doing it right and there is no catch somewhere.

Montag451
  • 1,168
  • 3
  • 14
  • 30
user1523271
  • 1,005
  • 2
  • 13
  • 27
  • Yes, this is exactly how I would do it. – junix Jan 30 '13 at 20:29
  • It looks alright. I would personally hoist the `exit(1)` out of the conditional "`if(E_EXIST==errno)`" part, and have it exit on all errors, and then handle more errors to make failures easier to diagnose. But it's fundamentally OK. – sheu Jan 30 '13 at 21:07

3 Answers3

2

You're not actually using any semaphore functionality. You could have the same effect with a regular file, use open with O_CREAT|O_EXCL and unlink on exit.
You could use the same file to write your PID in it ("pidfile") then if open fails read the PID and use it to check if the it belongs to another instance of your program or it's just there because it wasn't unlinked due to a crash.

bahaa
  • 199
  • 4
  • File requires cleanup if (when) process crashes. Pid files can be renamed, thus invalidating locking. Checking if the pid belongs an instance of your program can take effort to be sure, but an okay way may be to check the filename. There is a good answer here http://stackoverflow.com/questions/5339200/how-to-create-a-single-instance-application-in-c-or-c – null Oct 07 '16 at 13:34
1

The catch is that the logic fails to provide an iron-clad assurance that an instance of the application will execute. What if the existing application has already decided to exit, and is executing the exit path, but has not yet called sem_close? The new instance thinks "I am unnecessary" because the semaphore is still there, and exits. The net result is that nothing is running.

Whether this is a problem depends on the situation. You can get away with this kind of thing if it's an interactive app. PC users are accustomed to clicking on icons multiple times when stuff doesn't launch.

One way to solve the problem would be to use some IPC mechanism. For instance, the new instance of a server can contact the existing instance and place a request "please stay running, if possible". If the server cannot be contacted, or the response to the request is negative, then it can take over as the new instance.

You also need this if there is a requirement to pass on a request to the existing instance. Say the program has command line arguments and must take some action. Or, here is a familiar example: think of a browser: the user wants the OS to open a URL, and an existing browser instance is to be used. If a new browser isn't going to be launched, that URL has to be communicated to the existing instance as a request. It's not enough to just observe that there is an existing instance and quit, because the launch request is a event which was made for a reason: someone or something wants the program to do something. The logic that you have is only fine for a daemon type process which reads a configuration and then listens for requests, and whose launch is not a trigger for anything.

Kaz
  • 55,781
  • 9
  • 100
  • 149
1

I have just written one, and tested.

#define PID_FILE "/tmp/pidfile"
static void create_pidfile(void) {
    int fd = open(PID_FILE, O_RDWR | O_CREAT | O_EXCL, 0);

    close(fd);
}

int main(void) {
    int fd = open(PID_FILE, O_RDONLY);
    if (fd > 0) {
        close(fd);
        return 0;
    }

    // make sure only one instance is running
    create_pidfile();
}
Akagi201
  • 456
  • 5
  • 12
  • 1
    This code isn't removing the file when quitting. Also it isn't checking if the pid belongs to a running program. Pid files require cleanup if (when) process crashes. Pid files can be renamed, thus invalidating locking. Checking if the pid belongs an instance of your program can take effort to be sure, but an okay way may be to check the filename. There is a good answer here http://stackoverflow.com/questions/5339200/how-to-create-a-single-instance-application-in-c-or-c – null Oct 07 '16 at 13:36