【发布时间】:2012-06-04 13:41:42
【问题描述】:
我正在使用 Objective-c 在 Mac 中编写一个命令行应用程序
在应用程序启动时,我想检查同一应用程序的另一个实例是否已经在运行。如果是,那么我应该等待它完成或退出当前实例或退出另一个实例等。
有什么办法吗?
【问题讨论】:
标签: objective-c macos osx-lion osx-snow-leopard command-line-tool
我正在使用 Objective-c 在 Mac 中编写一个命令行应用程序
在应用程序启动时,我想检查同一应用程序的另一个实例是否已经在运行。如果是,那么我应该等待它完成或退出当前实例或退出另一个实例等。
有什么办法吗?
【问题讨论】:
标签: objective-c macos osx-lion osx-snow-leopard command-line-tool
对此的标准 Unix 解决方案是创建一个“运行文件”。当您启动时,您尝试创建该文件并将您的 pid 写入它(如果它不存在);如果确实存在,请从中读取 pid,如果有一个正在运行的程序具有该 pid 和您的进程名称,请等待/退出/随便什么。
问题是,你把那个文件放在哪里,你怎么称呼它?
首先,您必须确定“已经运行”的确切含义。显然不是“世界上的任何地方”,但它可以是从“当前机器上的任何地方”到“当前桌面会话中”的任何东西。 (例如,如果用户 A 启动您的程序,将其暂停,然后用户 B 出现并通过快速用户切换接管计算机,她是否能够运行该程序?)
对于这个问题的任何合理答案,都有一个明显的路径名模式。例如,在 Mac 上,/tmp 在系统范围内共享,而 $TMPDIR 特定于给定会话,因此 /tmp/${ARGV[0]}.pid 是表示“只有一个在机器上复制,句号”,而 ${TMPDIR}/${ARGV[0]}.pid 是说“每个会话只有一个副本”的好方法。
【讨论】:
flock 获取文件的排他锁。只有一个进程可以获取锁。如果锁失败,另一个进程拥有它。当该进程终止时,锁被释放。
执行此操作的简单但常见的方法是检查进程列表以获取可执行文件的名称。
ps - A | grep <your executable name>
【讨论】:
谢谢@abarnert。
这就是我目前实施的方式。在 main() 开始时,我会检查二进制文件自己的目录中是否存在名为 .lock 的文件(我正在考虑将其移动到 /tmp)。如果是,则应用程序退出。
如果没有,它将创建文件。 在应用程序结束时,.lock 文件被删除
我还没有将 pid 写入该文件,但在需要退出前一个实例时我会这样做(目前我还不需要它,但将来可能会用到)。 我认为可以使用 PID 检索
int myPID=[[NSProcessInfo processInfo] processIdentifier];
该程序将由作为根守护程序运行的自定义调度程序调用。所以它将以root身份运行。
看到答案,我会假设没有解决问题的直接方法。
【讨论】: