views:

2694

answers:

11

I'm working on a GUI application in WxPython, and I am not sure how I can ensure that only one copy of my application is running at any given time on the machine. Due to the nature of the application, running more than once doesn't make any sense, and will fail quickly. Under Win32, I can simply make a named mutex and check that at startup. Unfortunately, I don't know of any facilities in Linux that can do this.

I'm looking for something that will automatically be released should the application crash unexpectedly. I don't want to have to burden my users with having to manually delete lock files because I crashed.

+1  A: 

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

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

Bernard
+1  A: 

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

Example (from bash, for simplicity):

linux# pidof myapp
8947
linux# pidof nonexistent_app

linux#
Adam Liss
This is neat, less code required than the lockfile approach. Downside is it isn't exactly atomic, but for single instance detection, that may not be necessary.
Matt Green
This won't work if you're running "pidof app" from inside the app
MattSmith
It also won't work if there is a different running program with the same name, or if another user is also running the program.
CesarB
+1  A: 

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

+18  A: 

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

Robert Gamble
By convention, this should go under /var/run/, correct?
Matt Green
Out of curiosity, doesn't simply opening the file for exclusive access do the work of a mutex?
Menkboy
Menkboy, if the file is properly closed in the event of a crash, then I think that will work perfectly and simplify things further. Thank you.
Matt Green
This is the first description of pidfiles on SO I've seen that explains all the steps needed to make sure they work properly.Also, the last two steps can be done at once - checking /proc/pid/cmdline will fail if 'pid' isn't a running process, since the directory won't exist.
Branan
This appears to have a race condition? First, suppose an instance of my program dies, leaving behind the stale PID file. Then I start up two new instances of my program at the same time. The two new instances might both decide that the PID file is stale, and then one after another they will overwrite the PID file. This is not a problem for traditional UNIX daemons, which are only started at boot and by explicit administrator command-line choice. But it might be a problem for other programs.
user9876
+1  A: 

This is the Posix equivalent, I believe.

Menkboy
+1  A: 

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

Otherwise as Bernard suggested, you can use

import os
os.getpid()

And write it to /var/run/*application_name*.pid. When the process starts, it should check if the pid in /var/run/*application_name*.pid is listed in the ps table and quit if it is, otherwise write its own pid into /var/run/*application_name*.pid. In the following var_run_pid is the pid you read 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
MattSmith
+1 for suggesting SYSV semaphores, -1 for suggesting calling `ps` rather than something more efficient (say, `kill -0` -- via the signal call rather than the command if one prefers to avoid an extra fork/exec) and suggesting pidfiles without advisory locking (ie. flock) to avoid race conditions and PID collisions.
Charles Duffy
+18  A: 

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

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

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

Charles Duffy
I agree, this is probably the best method in most cases.
Robert Gamble
This is the correct method to lock, however its also good to write a PID file that is cleaned up on normal exit, as well as to create an entry in /var/lock/subsys (if it exists). This allows your program to realize if its re-starting from a crash, among other things. So, doing both helps.
Tim Post
@tinkertim - Not a bad suggestion, though it makes sense to flock() the pidfile rather than having more than one.
Charles Duffy
+4  A: 

Complete locking solution using 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(0)

HTH.

zgoda
+1  A: 

I found this link, which uses fcntl as suggested by others: Interprocess Synchronization in Python/Linux.

technomalogical
+4  A: 

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

  name = "MyApp-%s" % wx.GetUserId()
  checker = wx.SingleInstanceChecker(name)
  if checker.IsAnotherRunning():
      return False
Brian Victor
A: 

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

code w/ explanation

zdwiel