我正在使用WxPython中的GUI应用程序,我不确定如何确保在计算机上的任何给定时间只运行我的应用程序的一个副本.由于应用程序的性质,运行不止一次没有任何意义,并且会很快失败.在Win32下,我可以简单地创建一个名为mutex并在启动时检查它.不幸的是,我不知道Linux中可以做到这一点的任何设施.
如果应用程序意外崩溃,我正在寻找会自动发布的内容.我不想让我的用户不得不手动删除锁定文件,因为我崩溃了.
正确的事情是咨询锁定使用flock(LOCK_EX)
; 在Python中,这可以在fcntl
模块中找到.
与pidfiles不同,当你的进程因任何原因死亡时,这些锁总是自动释放,没有与文件删除相关的竞争条件(因为文件不需要被删除以释放锁),并且没有可能出现不同的情况进程继承PID,从而出现验证过时的锁.
如果你想要不清洁的关机检测,你可以在获取锁之后将标记(例如你的PID,传统主义者)写入文件,然后在干净关闭之前将文件截断为0字节状态(同时保持锁定); 因此,如果未保持锁定且文件非空,则指示不正常关闭.
使用该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)
有几种常用技术,包括使用信号量.我经常看到的最常用的是在启动时创建一个包含正在运行的进程的pid的"pid锁文件".如果程序启动时该文件已存在,请将其打开并抓取内部的pid,检查是否正在运行具有该pid的进程,如果检查/ proc/pid中的cmdline值是否为您的程序的实例,如果它然后退出,否则用您的pid覆盖该文件.pid文件的通常名称是application_name.pid
.
wxWidgets为此提供了一个wxSingleInstanceChecker类:wxPython doc或wxWidgets doc.wxWidgets doc在C++中有示例代码,但python等价物应该是这样的(未经测试):
name = "MyApp-%s" % wx.GetUserId() checker = wx.SingleInstanceChecker(name) if checker.IsAnotherRunning(): return False
这建立在用户zgoda的答案之上.它主要解决了与锁文件的写访问有关的棘手问题.特别是,如果首先创建锁定文件root
,foo
则由于缺少用户的写入权限,另一个用户无法成功地再次尝试重写此文件foo
.显而易见的解决方案似乎是为每个人创建具有写权限的文件.此解决方案还基于我的不同答案,必须创建具有此类自定义权限的文件.这个问题在现实世界中非常重要,您的程序可能由任何用户运行,包括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 /sf/ask/17360801/ 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/
其用作锁定文件的目录,但创建此目录需要root
权限.您可以自己决定使用哪个目录.
请注意,无需打开锁定文件的文件句柄.