How to create a single instance application in C o

2019-01-04 07:43发布

What would be your suggestion in order to create a single instance application, so that only one process is allowed to run at a time? File lock, mutex or what?

12条回答
走好不送
2楼-- · 2019-01-04 08:34

A good way is:

#include <sys/file.h>
#include <errno.h>

int pid_file = open("/var/run/whatever.pid", O_CREAT | O_RDWR, 0666);
int rc = flock(pid_file, LOCK_EX | LOCK_NB);
if(rc) {
    if(EWOULDBLOCK == errno)
        ; // another instance is running
}
else {
    // this is the first instance
}

Note that locking allows you to ignore stale pid files (i.e. you don't have to delete them). When the application terminates for any reason the OS releases the file lock for you.

Pid files are not terribly useful because they can be stale (the file exists but the process does not). Hence, the application executable itself can be locked instead of creating and locking a pid file.

A more advanced method is to create and bind a unix domain socket using a predefined socket name. Bind succeeds for the first instance of your application. Again, the OS unbinds the socket when the application terminates for any reason. When bind() fails another instance of the application can connect() and use this socket to pass its command line arguments to the first instance.

查看更多
小情绪 Triste *
3楼-- · 2019-01-04 08:37

You can create an "anonymous namespace" AF_UNIX socket. This is completely Linux-specific, but has the advantage that no filesystem actually has to exist.

Read the man page for unix(7) for more info.

查看更多
Emotional °昔
4楼-- · 2019-01-04 08:39

Here is a solution based on sem_open

/*
*compile with :
*gcc single.c -o single -pthread
*/

/*
 * run multiple instance on 'single', and check the behavior
 */
#include <stdio.h>
#include <fcntl.h>    
#include <sys/stat.h>        
#include <semaphore.h>
#include <unistd.h>
#include <errno.h>

#define SEM_NAME "/mysem_911"

int main()
{
  sem_t *sem;
  int rc; 

  sem = sem_open(SEM_NAME, O_CREAT, S_IRWXU, 1); 
  if(sem==SEM_FAILED){
    printf("sem_open: failed errno:%d\n", errno);
  }

  rc=sem_trywait(sem);

  if(rc == 0){ 
    printf("Obtained lock !!!\n");
    sleep(10);
    //sem_post(sem);
    sem_unlink(SEM_NAME);
  }else{
    printf("Lock not obtained\n");
  }
}

One of the comments on a different answer says "I found sem_open() rather lacking". I am not sure about the specifics of what's lacking

查看更多
迷人小祖宗
5楼-- · 2019-01-04 08:40

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();
}
查看更多
贪生不怕死
6楼-- · 2019-01-04 08:44

No one has mentioned it, but sem_open() creates a real named semaphore under modern POSIX-compliant OSes. If you give a semaphore an initial value of 1, it becomes a mutex (as long as it is strictly released only if a lock was successfully obtained).

With several sem_open()-based objects, you can create all of the common equivalent Windows named objects - named mutexes, named semaphores, and named events. Named events with "manual" set to true is a bit more difficult to emulate (it requires four semaphore objects to properly emulate CreateEvent(), SetEvent(), and ResetEvent()). Anyway, I digress.

Alternatively, there is named shared memory. You can initialize a pthread mutex with the "shared process" attribute in named shared memory and then all processes can safely access that mutex object after opening a handle to the shared memory with shm_open()/mmap(). sem_open() is easier if it is available for your platform (if it isn't, it should be for sanity's sake).

Regardless of the method you use, to test for a single instance of your application, use the trylock() variant of the wait function (e.g. sem_trywait()). If the process is the only one running, it will successfully lock the mutex. If it isn't, it will fail immediately.

Don't forget to unlock and close the mutex on application exit.

查看更多
叛逆
7楼-- · 2019-01-04 08:48

It will depend on which problem you want to avoid by forcing your application to have only one instance and the scope on which you consider instances.

For a daemon — the usual way is to have a /var/run/app.pid file.

For user application, I've had more problems with applications which prevented me to run them twice than with being able to run twice an application which shouldn't have been run so. So the answer on "why and on which scope" is very important and will probably bring answer specific on the why and the intended scope.

查看更多
登录 后发表回答