确保Linux中的单个应用程序实例

时间:2008-10-21 01:58:31

标签: python linux single-instance

我正在使用WxPython中的GUI应用程序,我不确定如何确保在计算机上的任何给定时间只运行我的应用程序的一个副本。由于应用程序的性质,运行不止一次没有任何意义,并且会很快失败。在Win32下,我可以简单地创建一个名为mutex并在启动时检查它。不幸的是,我不知道Linux中可以做到这一点的任何设施。

如果应用程序意外崩溃,我正在寻找会自动发布的内容。

,我不想让我的用户不得不手动删除锁定文件

12 个答案:

答案 0 :(得分:60)

正确的事情是使用flock(LOCK_EX)进行咨询锁定;在Python中,这可以在fcntl module

中找到

与pidfiles不同,当您的进程因任何原因而死亡时,这些锁始终会自动释放,没有与文件删除相关的竞争条件(因为文件不会需要被删除以释放锁定),并且不可能有一个不同的进程继承PID,从而出现验证过时的锁。

如果你想要不干净的关闭检测,你​​可以在获取锁之后将标记(例如你的PID,传统主义者)写入文件,然后在干净关闭之前将文件截断为0字节状态(同时锁定正在举行);因此,如果未保持锁定且文件非空,则表示发生了不正常的关闭。

答案 1 :(得分:28)

使用fcntl模块完成锁定解决方案:

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)

答案 2 :(得分:25)

有几种常用技术,包括使用信号量。我经常看到的最常用的是在启动时创建一个包含正在运行的进程的pid的“pid锁文件”。如果程序启动时该文件已存在,请将其打开并抓取内部的pid,检查是否正在运行具有该pid的进程,如果它正在检查/ proc / pid中的cmdline值查看它是否是您的程序的实例,如果它然后退出,否则用您的pid覆盖该文件。 pid文件的通常名称是 application_name .pid

答案 3 :(得分:8)

wxWidgets为此提供了一个wxSingleInstanceChecker类:​​wxPython docwxWidgets doc。 wxWidgets doc在C ++中有示例代码,但python等价物应该是这样的(未经测试):

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

答案 4 :(得分:6)

这建立在用户answerzgoda之上。它主要解决了与锁文件的写访问有关的棘手问题。特别是,如果锁定文件最初是由root创建的,则由于缺少用户foo的写入权限,另一个用户foo无法成功地再次尝试重写此文件。显而易见的解决方案似乎是为每个人创建具有写权限的文件。此解决方案还基于我的不同answer,必须创建具有此类自定义权限的文件。在您的程序可能由任何用户运行的现实世界中,这一问题非常重要,包括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)

上述代码的限制是,如果锁定文件已存在且具有意外权限,则不会更正这些权限。

我希望使用/var/run/<appname>/作为锁定文件的目录,但创建此目录需要root权限。您可以自己决定使用哪个目录。

请注意,无需打开锁定文件的文件句柄。

答案 5 :(得分:4)

这是基于TCP端口的解决方案:

# 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)

答案 6 :(得分:1)

我相信

The set of functions defined in semaphore.h - sem_open()sem_trywait()等 - 是POSIX的等价物。

答案 7 :(得分:1)

查找一个与unix上的SYSV信号量接口的python模块。信号量具有SEM_UNDO标志,如果进程崩溃,将导致进程保留的资源被释放。

否则,正如伯纳德建议的那样,你可以使用

import os
os.getpid()

并将其写入/var/run/application_name.pid。当进程开始时,它应检查/var/run/application_name.pid中的pid是否列在ps表中并退出(如果是),否则将其自己的pid写入/ var / run / APPLICATION_NAME .pid。在下面的var_run_pid中是您从/ var / run / application_name .pid

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

答案 8 :(得分:0)

如果您创建了一个锁定文件并将pid放入其中,您可以检查它的进程ID并告诉您是否崩溃了,不是吗?

我个人没有这样做,所以请加入适量的盐。 :P

答案 9 :(得分:0)

你能使用'pidof'实用程序吗?如果您的应用正在运行,pidof会将您应用的进程ID写入stdout。如果没有,它将打印换行符(LF)并返回错误代码。

示例(来自bash,为简单起见):

linux# pidof myapp
8947
linux# pidof nonexistent_app

linux#

答案 10 :(得分:0)

到目前为止,最常见的方法是将文件放入/ var / run / called [application] .pid,它只包含正在运行的进程的PID或父进程。 作为替代方案,您可以在同一目录中创建命名管道,以便能够将消息发送到活动进程,例如,打开一个新文件。

答案 11 :(得分:0)

当您希望能够将后续尝试实例的命令行参数传递给第一个应用程序时,我已经为运行这些类型的应用程序创建了一个基本框架。如果实例未找到已在其中侦听的实例,则实例将开始侦听预定义端口。如果某个实例已经存在,它会通过套接字发送其命令行参数并退出。

code w/ explanation

相关问题