Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

One-instance only application in C and Linux [duplicate]

Tags:

c

linux

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.

like image 869
user1523271 Avatar asked Jan 30 '13 20:01

user1523271


3 Answers

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.

like image 142
bahaa Avatar answered Oct 12 '22 20:10

bahaa


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.

like image 20
Kaz Avatar answered Oct 12 '22 20:10

Kaz


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();
}
like image 25
Akagi201 Avatar answered Oct 12 '22 18:10

Akagi201