如何防止多个进程创建另一个进程的多个实例?

1 投票
2 回答
777 浏览
提问于 2025-04-18 10:43

我有两个进程:一个叫“开始”,另一个叫“状态”。“开始”进程可以同时运行多个,而“状态”进程只能有一个。

当“开始”进程启动时,它会尝试启动“状态”进程。目前,我的做法是让“状态”进程检查它的服务器端口是否已经被占用,以此来判断是否已经有另一个“状态”进程在运行。如果发现有,就让它优雅地关闭。

但是,这样做存在一个问题,叫做“竞争条件”。也就是说,当它检查端口是否被占用的时候,可能已经有另一个“状态”进程在进行同样的检查并且正在绑定这个端口,这样就可能会出现两个“状态”进程。

有没有什么方法可以解决这个问题呢?我考虑过让另一个进程来监控系统中“状态”进程的数量,但还有没有其他的办法呢?

补充说明:这是用Python 2.6写的。

补充说明2:两个进程都是从命令行执行的。

2 个回答

0

可能有更符合Python风格的方法,但我个人会使用一些进程管理工具,比如daemontools、systemd、runit等。这些工具可以帮助你启动和监控一个程序,确保它只运行一个实例。

2

首先,你可以使用像 supervisord 这样的工具来协调进程的运行。这个工具其实挺不错的。你只需要配置你的进程,比如可以同时运行的最大数量等等,它会帮你处理其他的事情。不过,你得搞清楚所有的小配置项。还有,如果你有一个状态进程在另一个进程里作为线程运行,可能想把它单独拿出来,这样会更好。

如果你改变一下处理方式,可能会让这个问题变得简单一些。与其先检查再执行,不如直接执行,然后处理可能出现的错误。

try: 
    open_port_listener()
except socket.error as e:
    do_nothing()

或者,也许可以对套接字错误进行更细致的检查。我假设你在使用 socket,并且遇到了 socket.error(可能是地址已经在使用之类的错误?)。

如果你是使用 multiprocessing 模块来运行这个程序(我知道你不是,因为你已经澄清过了,但我还是留着这段,以防对其他人有用),你可以使用锁来确保状态进程的检查只在一个进程中进行。multiprocessing 模块支持这个功能。你可以在 这里 查看文档。

from multiprocessing import Process, Lock

def startStatusProcess(l):
    l.acquire()    
    if not do_check():
        Process(target=runStatusProcess, args=()).start()
    l.release() 

if __name__ == '__main__':
    lock = Lock()
    startStatusProcess(lock)

撰写回答