Objective c 如何检查应用程序/二进制文件的另一个实例是否已在运行

Objective c 如何检查应用程序/二进制文件的另一个实例是否已在运行,objective-c,macos,osx-lion,osx-snow-leopard,command-line-tool,Objective C,Macos,Osx Lion,Osx Snow Leopard,Command Line Tool,我正在用Objective-c在Mac中编写一个命令行应用程序 在应用程序开始时,我想检查同一应用程序的另一个实例是否已经在运行。如果是,那么我应该要么等待它完成,要么退出当前实例,要么退出另一个实例,等等 有什么方法可以做到这一点吗?简单但常用的方法是在进程列表中查找可执行文件的名称 ps-A | grep简单但常用的方法是检查进程列表中可执行文件的名称 ps-A | grep这方面的标准Unix解决方案是创建一个运行文件。当您启动时,您尝试创建该文件,如果该文件不存在,则将pid写入该文件;

我正在用Objective-c在Mac中编写一个命令行应用程序

在应用程序开始时,我想检查同一应用程序的另一个实例是否已经在运行。如果是,那么我应该要么等待它完成,要么退出当前实例,要么退出另一个实例,等等


有什么方法可以做到这一点吗?

简单但常用的方法是在进程列表中查找可执行文件的名称


ps-A | grep

简单但常用的方法是检查进程列表中可执行文件的名称


ps-A | grep

这方面的标准Unix解决方案是创建一个运行文件。当您启动时,您尝试创建该文件,如果该文件不存在,则将pid写入该文件;如果它确实存在,则从中读取pid,如果有一个正在运行的程序具有该pid和您的进程名,则等待/退出/无论什么

问题是,你把那个文件放在哪里,你叫它什么

首先,你必须决定已经运行到底意味着什么。显然不是世界上的任何地方,但它可以是任何东西,从当前计算机上的任何位置到当前桌面会话中的任何位置。例如,如果用户A启动并暂停您的程序,然后用户B出现并通过快速用户切换接管计算机,那么她是否能够运行该程序


对于这个问题的任何合理答案,都有一个明显的路径名模式。例如,在Mac上,/tmp是全系统共享的,而$TMPDIR是特定于给定会话的,因此,例如,/tmp/${ARGV[0]}.pid是表示计算机上只有一个副本的好方法,period,而${TMPDIR}/${ARGV[0]}.pid是表示每个会话只有一个副本的好方法。

这方面的标准Unix解决方案是创建一个运行文件。当您启动时,您尝试创建该文件,如果该文件不存在,则将pid写入该文件;如果它确实存在,则从中读取pid,如果有一个正在运行的程序具有该pid和您的进程名,则等待/退出/无论什么

问题是,你把那个文件放在哪里,你叫它什么

首先,你必须决定已经运行到底意味着什么。显然不是世界上的任何地方,但它可以是任何东西,从当前计算机上的任何位置到当前桌面会话中的任何位置。例如,如果用户A启动并暂停您的程序,然后用户B出现并通过快速用户切换接管计算机,那么她是否能够运行该程序

对于这个问题的任何合理答案,都有一个明显的路径名模式。例如,在Mac上,/tmp是全系统共享的,而$TMPDIR是特定于给定会话的,因此,例如,/tmp/${ARGV[0]}.pid是表示机器上只有一个副本的好方法,period,而${TMPDIR}/${ARGV[0]}.pid是表示每个会话只有一个副本的好方法。

谢谢@abarnert

这就是我目前实施的方式。在main的开头,我将检查二进制文件自己的目录中是否存在名为.lock的文件,我正在考虑将其移动到/tmp。如果是,则应用程序退出

如果没有,它将创建该文件。 在应用程序结束时,删除.lock文件

我还没有将pid写入该文件,但在退出之前的实例时,我会这样做,因为我不需要它,但将来可能需要它。 我认为PID可以使用

int myPID=[[NSProcessInfo processInfo] processIdentifier];
该程序将由作为根守护进程运行的自定义计划程序调用。所以它将作为root运行

看到答案,我认为没有直接的方法来解决这个问题。

谢谢@abarnert

这就是我目前实施的方式。在main的开头,我将检查二进制文件自己的目录中是否存在名为.lock的文件,我正在考虑将其移动到/tmp。如果是,则应用程序退出

如果没有,它将创建该文件。 在应用程序结束时,删除.lock文件

我还没有将pid写入该文件,但在退出之前的实例时,我会这样做,因为我不需要它,但将来可能需要它。 我认为PID可以使用

int myPID=[[NSProcessInfo processInfo] processIdentifier];
该程序将由作为根守护进程运行的自定义计划程序调用。所以它将作为root运行


看到答案,我会认为没有直接的方法来解决问题。

谢谢,我已经用类似的方式做了,我想会有更好的/直接的方法。我将在下面解释我是如何做到这一点的。当前机器上的任何地方都是我需要的。@abarnert你没有比赛条件吗?在正常情况下不太可能发生这种情况,但如果进程频繁/自动启动,则出现竞态条件的概率更高。@ring0:是的,一个简单的实现有竞态条件,但有多种方法可以解决这一问题。基本上,它们都涉及乐观地做事,并在意外失败时重试循环。例如

您可以在摆弄权限的同时执行原子写入临时和重命名,因此如果两个进程都尝试,其中一个进程将失败并重试。或者,您也可以只在适当的位置创建和写入文件;一个进程可以看到现有文件,但看不到任何内容,在这种情况下,它必须重试。等等。最常见的解决方案没有考虑的一个问题是,一个进程可能会死亡,留下它的pid文件,然后两个新副本启动,其中一个具有与被放弃的相同的pid。您可以通过编写pid加上启动时间戳来解决这个问题,但是接下来您需要一种方法来获取另一个进程的启动时间,这在跨平台上很难做到……如果您要做到这一点,请不要乱动pid。只需使用flock即可获得文件的独占锁。只有一个进程可以获得锁。如果锁失败,另一个进程将拥有它。当该进程终止时,锁被释放。谢谢,我已经用类似的方式完成了这项工作,我想会有更好的/直接的方法。我将在下面解释我是如何做到这一点的。当前机器上的任何地方都是我需要的。@abarnert你没有比赛条件吗?在正常情况下不太可能发生这种情况,但如果进程频繁/自动启动,则出现竞态条件的概率更高。@ring0:是的,一个简单的实现有竞态条件,但有多种方法可以解决这一问题。基本上,它们都涉及乐观地做事,并在意外失败时重试循环。例如,您可以在摆弄权限的同时执行原子写入临时和重命名,因此如果两个进程都尝试,其中一个进程将失败并重试。或者,您也可以只在适当的位置创建和写入文件;一个进程可以看到现有文件,但看不到任何内容,在这种情况下,它必须重试。等等。最常见的解决方案没有考虑的一个问题是,一个进程可能会死亡,留下它的pid文件,然后两个新副本启动,其中一个具有与被放弃的相同的pid。您可以通过编写pid加上启动时间戳来解决这个问题,但是接下来您需要一种方法来获取另一个进程的启动时间,这在跨平台上很难做到……如果您要做到这一点,请不要乱动pid。只需使用flock即可获得文件的独占锁。只有一个进程可以获得锁。如果锁失败,另一个进程将拥有它。当该进程终止时,锁被释放。首先,正如您所暗示的,这就是您如何杀死或以其他方式向已经运行的副本发送信号的方法,这是您在原始问题中要求的选项之一。其次,它可以让您区分崩溃进程留下的废弃文件和活动文件,例如,通过使用信号0执行kill。对,没有直接的方法可以做到这一点。间接方法有很多种,但它们都可以归结为两种:某种可预测命名的东西pidfile、socket、命名管道、NT命名内核互斥体,或者某种广播机制Mac分布式通知、Windows WM_uu广播消息等。。例如,有一些库总结了一些Python解决方案的详细信息,尽管我所知道的唯一的C和ObjC库是大型框架的一部分。我仍然对“锁文件”概念存在问题。现在我考虑使用ps-ef | grep | grep-vE'grep'| awk'{print$2}',然后捕获输出并检查行数以了解实例数及其pid。在这种情况下,我也可以通过检查pid来杀死其他实例=粘虫。我必须检查如何通过NSTask发出命令,并使用NSPipe捕获它。有什么建议吗?解析ps确实不是一个好的答案,原因有很多。锁定文件的概念有哪些问题?您可能想看看linux发行版中的.rc脚本,看看它们是如何处理细节的。对于不同的命令行参数,某些二进制文件具有不同的功能。调度程序可以根据重复间隔同时执行其中一些二进制文件。在这种情况下,锁定文件概念会随机失败。我检查了锁文件是否存在,并在相邻的行中创建了锁文件,但如果同时启动了4或5个二进制实例,则2或3个实例通过了锁文件是否存在检查。哪些是.rc脚本,您指的是rc.d/init.d脚本还是bashrc?编写pid有两个原因。首先,正如您所暗示的,这就是您如何杀死或以其他方式向已经运行的副本发送信号的方法,这是您在原始问题中要求的选项之一。其次,它可以让您区分崩溃进程留下的废弃文件和活动文件,例如,通过使用信号0执行kill。对,没有直接的方法可以做到这一点。间接的方法有很多种,但它们都可以归结为两件事:某种可预测的命名方法
pidfile、socket、命名管道、NT命名内核互斥体,或某种广播机制Mac分布式通知、Windows WM_uu广播消息等。。例如,有一些库总结了一些Python解决方案的详细信息,尽管我所知道的唯一的C和ObjC库是大型框架的一部分。我仍然对“锁文件”概念存在问题。现在我考虑使用ps-ef | grep | grep-vE'grep'| awk'{print$2}',然后捕获输出并检查行数以了解实例数及其pid。在这种情况下,我也可以通过检查pid来杀死其他实例=粘虫。我必须检查如何通过NSTask发出命令,并使用NSPipe捕获它。有什么建议吗?解析ps确实不是一个好的答案,原因有很多。锁定文件的概念有哪些问题?您可能想看看linux发行版中的.rc脚本,看看它们是如何处理细节的。对于不同的命令行参数,某些二进制文件具有不同的功能。调度程序可以根据重复间隔同时执行其中一些二进制文件。在这种情况下,锁定文件概念会随机失败。我检查了锁文件是否存在,并在相邻的行中创建了锁文件,但如果同时启动了4或5个二进制实例,则2或3个实例通过了锁文件是否存在检查。哪些是.rc脚本,您指的是rc.d/init.d脚本还是bashrc?