How to create one instance application in C or C ++

What would be your suggestion to create one instance application so that only one process can start at a time? Lock files, mutex or what?

+43
c ++ c linux
Mar 17 2018-11-11T00:
source share
11 answers

Good way:

#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 obsolete pid files (i.e. you do not need to delete them). When the application is terminated for any reason, the OS releases the file lock for you.

Pid files are not very useful because they may be outdated (the file exists, but the process does not work). Therefore, the application executable itself may be locked instead of creating and locking the pid file.

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

+51
Mar 17 '11 at 13:24
source share

Here is the solution in C ++. It uses Maxim socket recommendations. I like this solution better than the file-based locking solution because file-based crashes if the process crashes and does not delete the lock file. Another user will not be able to delete the file and lock it. Sockets are automatically deleted when the process ends.

Using:

 int main() { SingletonProcess singleton(5555); // pick a port number to use that is specific to this app if (!singleton()) { cerr << "process running already. See " << singleton.GetLockFileName() << endl; return 1; } ... rest of the app } 

The code:

 #include <netinet/in.h> class SingletonProcess { public: SingletonProcess(uint16_t port0) : socket_fd(-1) , rc(1) , port(port0) { } ~SingletonProcess() { if (socket_fd != -1) { close(socket_fd); } } bool operator()() { if (socket_fd == -1 || rc) { socket_fd = -1; rc = 1; if ((socket_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { throw std::runtime_error(std::string("Could not create socket: ") + strerror(errno)); } else { struct sockaddr_in name; name.sin_family = AF_INET; name.sin_port = htons (port); name.sin_addr.s_addr = htonl (INADDR_ANY); rc = bind (socket_fd, (struct sockaddr *) &name, sizeof (name)); } } return (socket_fd != -1 && rc == 0); } std::string GetLockFileName() { return "port " + std::to_string(port); } private: int socket_fd = -1; int rc; uint16_t port; }; 
+8
Oct 30 '14 at 19:02
source share

Avoid file based locking

It is always useful to avoid the file-based locking mechanism to implement an instance of a singleton application. The user can always rename the lock file to another name and run the application again as follows:

 mv lockfile.pid lockfile1.pid 

Where lockfile.pid is the lock file, on the basis of which the presence is checked before starting the application.

Thus, it is always preferable to use an object lock scheme that is directly visible only to the kernel. So, everything related to the file system is not reliable.

Thus, binding to an inet socket would be a better option. Please note that unix domain sockets are located on the file system and are not reliable.

Alternatively, you can also do this with DBUS.

+5
Aug 19 '14 at 7:44
source share

For windows, a named kernel object (for example, CreateEvent, CreateMutex). For unix, pid file - create a file and write the process ID to it.

+4
Mar 17 '11 at 12:51
source share

It depends on what problem you want to avoid, forcing the application to have only one instance and the scope of the instances.

For deamon, the usual way is to have the file /var/run/app.pid .

For the user application, I had more problems with applications that prevented me from running them twice than with the ability to run the application twice, which should not have run. Thus, the answer to the question “why and in what area” is very important and will probably answer a specific question about the reasons and the proposed scope.

+3
Mar 17 '11 at 13:13
source share

It does not seem to be mentioned - it is possible to create a mutex in shared memory, but it should be marked as shared by attributes (not verified):

 pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED); pthread_mutex_t *mutex = shmat(SHARED_MEMORY_ID, NULL, 0); pthread_mutex_init(mutex, &attr); 

There are also shared memory semaphores (but I could not figure out how to block them):

 int sem_id = semget(SHARED_MEMORY_KEY, 1, 0); 
+3
Sep 16 2018-11-11T00:
source share

You can create an "anonymous namespace" for AF_UNIX sockets. This is entirely Linux dependent, but has the advantage that the file system does not actually exist.

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

+2
Mar 17 2018-11-11T00:
source share

No one mentioned this, but sem_open() creates a real semaphore with the name in modern POSIX-compatible operating systems. If you give the semaphore an initial value of 1, it becomes a mutex (if it is strictly released, only if the lock was successfully received).

With several objects based on sem_open() , you can create all common equivalent objects called Windows - named mutexes, semaphores, and named events. Named events with a “manual” set to true are somewhat more difficult to emulate (for the correct emulation of CreateEvent() , SetEvent() and ResetEvent() ) four semaphore objects are required. Anyway, I'm distracted.

Shared memory is named as an alternative. You can initialize mutex pthread with the attribute "shared process" in named shared memory, and then all processes can safely access this mutex object after opening the descriptor in shared memory with shm_open() / mmap() . sem_open() easier if it is available for your platform (if it is not, this should be reasonable).

Regardless of the method you use to test one instance of your application, use the trylock() option of the trylock() function (e.g. sem_trywait() ). If only one process runs, it will successfully lock the mutex. If it is not, it will work immediately.

Remember to unlock and close the mutex when you exit the application.

+1
Nov 03 '13 at 3:36
source share

Based on the maxim answer hints, here is my POSIX solution for a dual-processor daemon (that is, the only application that can act as a daemon and as a client communicating with this daemon). This scheme has the advantage of providing an elegant solution to the problem when the first launched instance should be a daemon, and all subsequent executions should just load work on this daemon. This is a complete example, but there is not enough material that a real daemon needs to do (for example, using syslog to log and fork to properly position itself in the background , reset privileges, etc.), but it is already quite long and fully works as is. I have only tested this on Linux so far, but IIRC should be POSIX compatible.

In the example, clients can send integers passed to them as the first command line argument, and are parsed using atoi through the daemon socket, which prints it to stdout . With such sockets, you can also transfer arrays, structures, and even file descriptors (see man 7 unix ).

 #include <stdio.h> #include <stddef.h> #include <stdbool.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <signal.h> #include <sys/socket.h> #include <sys/un.h> #define SOCKET_NAME "/tmp/exampled" static int socket_fd = -1; static bool isdaemon = false; static bool run = true; /* returns * -1 on errors * 0 on successful server bindings * 1 on successful client connects */ int singleton_connect(const char *name) { int len, tmpd; struct sockaddr_un addr = {0}; if ((tmpd = socket(AF_UNIX, SOCK_DGRAM, 0)) < 0) { printf("Could not create socket: '%s'.\n", strerror(errno)); return -1; } /* fill in socket address structure */ addr.sun_family = AF_UNIX; strcpy(addr.sun_path, name); len = offsetof(struct sockaddr_un, sun_path) + strlen(name); int ret; unsigned int retries = 1; do { /* bind the name to the descriptor */ ret = bind(tmpd, (struct sockaddr *)&addr, len); /* if this succeeds there was no daemon before */ if (ret == 0) { socket_fd = tmpd; isdaemon = true; return 0; } else { if (errno == EADDRINUSE) { ret = connect(tmpd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un)); if (ret != 0) { if (errno == ECONNREFUSED) { printf("Could not connect to socket - assuming daemon died.\n"); unlink(name); continue; } printf("Could not connect to socket: '%s'.\n", strerror(errno)); continue; } printf("Daemon is already running.\n"); socket_fd = tmpd; return 1; } printf("Could not bind to socket: '%s'.\n", strerror(errno)); continue; } } while (retries-- > 0); printf("Could neither connect to an existing daemon nor become one.\n"); close(tmpd); return -1; } static void cleanup(void) { if (socket_fd >= 0) { if (isdaemon) { if (unlink(SOCKET_NAME) < 0) printf("Could not remove FIFO.\n"); } else close(socket_fd); } } static void handler(int sig) { run = false; } int main(int argc, char **argv) { switch (singleton_connect(SOCKET_NAME)) { case 0: { /* Daemon */ struct sigaction sa; sa.sa_handler = &handler; sigemptyset(&sa.sa_mask); if (sigaction(SIGINT, &sa, NULL) != 0 || sigaction(SIGQUIT, &sa, NULL) != 0 || sigaction(SIGTERM, &sa, NULL) != 0) { printf("Could not set up signal handlers!\n"); cleanup(); return EXIT_FAILURE; } struct msghdr msg = {0}; struct iovec iovec; int client_arg; iovec.iov_base = &client_arg; iovec.iov_len = sizeof(client_arg); msg.msg_iov = &iovec; msg.msg_iovlen = 1; while (run) { int ret = recvmsg(socket_fd, &msg, MSG_DONTWAIT); if (ret != sizeof(client_arg)) { if (errno != EAGAIN && errno != EWOULDBLOCK) { printf("Error while accessing socket: %s\n", strerror(errno)); exit(1); } printf("No further client_args in socket.\n"); } else { printf("received client_arg=%d\n", client_arg); } /* do daemon stuff */ sleep(1); } printf("Dropped out of daemon loop. Shutting down.\n"); cleanup(); return EXIT_FAILURE; } case 1: { /* Client */ if (argc < 2) { printf("Usage: %s <int>\n", argv[0]); return EXIT_FAILURE; } struct iovec iovec; struct msghdr msg = {0}; int client_arg = atoi(argv[1]); iovec.iov_base = &client_arg; iovec.iov_len = sizeof(client_arg); msg.msg_iov = &iovec; msg.msg_iovlen = 1; int ret = sendmsg(socket_fd, &msg, 0); if (ret != sizeof(client_arg)) { if (ret < 0) printf("Could not send device address to daemon: '%s'!\n", strerror(errno)); else printf("Could not send device address to daemon completely!\n"); cleanup(); return EXIT_FAILURE; } printf("Sent client_arg (%d) to daemon.\n", client_arg); break; } default: cleanup(); return EXIT_FAILURE; } cleanup(); return EXIT_SUCCESS; } 
0
Apr 17 '13 at 23:30
source share

I just wrote 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(); } 
0
Jun 25 '14 at 2:10
source share

Just run this code in a separate thread:

 void lock() { while(1) { ofstream closer("myapplock.locker", ios::trunc); closer << "locked"; closer.close(); } } 

Run this as your main code:

 int main() { ifstream reader("myapplock.locker"); string s; reader >> s; if (s != "locked") { //your code } return 0; } 
0
Mar 18 '17 at 18:51
source share



All Articles