[ACCEPTED]-Ensure a single instance of an application in Linux-single-instance

Accepted answer
Score: 62

The Right Thing is advisory locking using 16 flock(LOCK_EX); in Python, this is found in the fcntl module.

Unlike 15 pidfiles, these locks are always automatically 14 released when your process dies for any 13 reason, have no race conditions exist relating 12 to file deletion (as the file doesn't need to 11 be deleted to release the lock), and there's 10 no chance of a different process inheriting 9 the PID and thus appearing to validate a 8 stale lock.

If you want unclean shutdown 7 detection, you can write a marker (such 6 as your PID, for traditionalists) into the 5 file after grabbing the lock, and then truncate 4 the file to 0-byte status before a clean 3 shutdown (while the lock is being held); thus, if 2 the lock is not held and the file is non-empty, an 1 unclean shutdown is indicated.

Score: 32

Complete locking solution using the fcntl module:

import fcntl
pid_file = 'program.pid'
fp = open(pid_file, 'w')
try:
    fcntl.lockf(fp, fcntl.LOCK_EX | fcntl.LOCK_NB)
except IOError:
    # another instance is running
    sys.exit(1)

0

Score: 25

There are several common techniques including 12 using semaphores. The one I see used most 11 often is to create a "pid lock file" on 10 startup that contains the pid of the running 9 process. If the file already exists when 8 the program starts up, open it up and grab 7 the pid inside, check to see if a process 6 with that pid is running, if it is check 5 the cmdline value in /proc/pid to see if it 4 is an instance of your program, if it is 3 then quit, otherwise overwrite the file 2 with your pid. The usual name for the pid 1 file is application_name.pid.

Score: 8

wxWidgets offers a wxSingleInstanceChecker 4 class for this purpose: wxPython doc, or wxWidgets doc. The wxWidgets 3 doc has sample code in C++, but the python 2 equivalent should be something like this 1 (untested):

  name = "MyApp-%s" % wx.GetUserId()
  checker = wx.SingleInstanceChecker(name)
  if checker.IsAnotherRunning():
      return False
Score: 6

This builds upon the answer by user zgoda. It mainly 22 addresses a tricky concern having to do 21 with write access to the lock file. In particular, if 20 the lock file was first created by root, another 19 user foo can then no successfully longer attempt 18 to rewrite this file due to an absence of 17 write permissions for user foo. The obvious 16 solution seems to be to create the file 15 with write permissions for everyone. This 14 solution also builds upon a different answer by 13 me, having to do creating a file with such 12 custom permissions. This concern is important 11 in the real world where your program may 10 be run by any user including root.

import fcntl, os, stat, tempfile

app_name = 'myapp'  # <-- Customize this value

# Establish lock file settings
lf_name = '.{}.lock'.format(app_name)
lf_path = os.path.join(tempfile.gettempdir(), lf_name)
lf_flags = os.O_WRONLY | os.O_CREAT
lf_mode = stat.S_IWUSR | stat.S_IWGRP | stat.S_IWOTH  # This is 0o222, i.e. 146

# Create lock file
# Regarding umask, see https://stackoverflow.com/a/15015748/832230
umask_original = os.umask(0)
try:
    lf_fd = os.open(lf_path, lf_flags, lf_mode)
finally:
    os.umask(umask_original)

# Try locking the file
try:
    fcntl.lockf(lf_fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
except IOError:
    msg = ('Error: {} may already be running. Only one instance of it '
           'can run at a time.'
           ).format('appname')
    exit(msg)

A limitation 9 of the above code is that if the lock file 8 already existed with unexpected permissions, those 7 permissions will not be corrected.

I would've 6 liked to use /var/run/<appname>/ as the directory for the lock 5 file, but creating this directory requires 4 root permissions. You can make your own decision 3 for which directory to use.

Note that there 2 is no need to open a file handle to the 1 lock file.

Score: 4

Here's the TCP port-based solution:

# Use a listening socket as a mutex against multiple invocations
import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('127.0.0.1', 5080))
s.listen(1)

0

Score: 1

The set of functions defined in semaphore.h -- sem_open(), sem_trywait(), etc -- are the POSIX equivalent, I 1 believe.

Score: 1

Look for a python module that interfaces 11 to SYSV semaphores on unix. The semaphores 10 have a SEM_UNDO flag which will cause the 9 resources held by the a process to be released 8 if the process crashes.

Otherwise as Bernard 7 suggested, you can use

import os
os.getpid()

And write it to /var/run/application_name.pid. When 6 the process starts, it should check if the 5 pid in /var/run/application_name.pid is listed in the ps 4 table and quit if it is, otherwise write 3 its own pid into /var/run/application_name.pid. In the 2 following var_run_pid is the pid you read 1 from /var/run/application_name.pid

cmd = "ps -p %s -o comm=" % var_run_pid
app_name = os.popen(cmd).read().strip()
if len(app_name) > 0:
    Already running
Score: 0

If you create a lock file and put the pid 4 in it, you can check your process id against 3 it and tell if you crashed, no?

I haven't 2 done this personally, so take with appropriate 1 amounts of salt. :p

Score: 0

Can you use the 'pidof' utility? If your 4 app is running, pidof will write the Process 3 ID of your app to stdout. If not, it will 2 print a newline (LF) and return an error 1 code.

Example (from bash, for simplicity):

linux# pidof myapp
8947
linux# pidof nonexistent_app

linux#
Score: 0

By far the most common method is to drop 6 a file into /var/run/ called [application].pid 5 which contains only the PID of the running 4 process, or parent process. As an alternative, you 3 can create a named pipe in the same directory 2 to be able to send messages to the active 1 process, e.g. to open a new file.

Score: 0

I've made a basic framework for running 9 these kinds of applications when you want 8 to be able to pass the command line arguments 7 of subsequent attempted instances to the 6 first one. An instance will start listening 5 on a predefined port if it does not find 4 an instance already listening there. If 3 an instance already exists, it sends its 2 command line arguments over the socket and 1 exits.

code w/ explanation

More Related questions