【发布时间】:2011-02-27 05:00:02
【问题描述】:
在 Linux 平台上,进程(C++ 应用程序)检查其实例尚未运行的最佳方法是什么?
【问题讨论】:
在 Linux 平台上,进程(C++ 应用程序)检查其实例尚未运行的最佳方法是什么?
【问题讨论】:
执行此操作的标准方法是在某处创建一个 pidfile,通常包含程序的 pid。
你不需要把pid放在那里,你可以在它上面放一个排他锁。如果您打开它进行读/写并使用 LOCK_EX | 聚集它LOCK_NB,如果文件已经被锁定,它将失败。这是无竞争条件的,如果程序崩溃,锁会自动释放。
通常您希望为每个用户执行此操作,因此用户的主目录是放置文件的好地方。
如果它是一个守护进程,像 /var/run 这样的地方会更好。
【讨论】:
对于桌面应用程序,检查是否为当前用户启动了一个实例可能更可行,以便两个用户可以运行自己的实例。
您可以使用一些库(libunique (GTK+) 或 QtSingleApplication (Qt)),或者自己做。除了前面提到的 pid 文件之外,您还可以在用户主目录的某个位置打开 FIFO 或 UNIX 域套接字。这样,您可以与正在运行的实例进行通信,例如。提高运行实例的窗口或告诉运行实例打开新文件/URI/whatever。
【讨论】:
您可以使用POSIX named semaphore 来执行此操作。这比使用文件锁要安全得多。
【讨论】:
Michael 解决方案的一个相关替代方案是在已知位置(可能在 /var/run 或 /tmp 下)创建一个目录,并使用系统调用的成功/失败作为确保互斥的机制。这与 CVS 多年来使用的互斥技巧相同,因为目录创建在大多数(可能是所有)商品操作系统上都是原子的。在目录 + PID 创建进程意外死亡并且无法清理的情况下,PID 文件仍然有用。此外,在检查现有目录 + PID 是否有效时,我建议明确检查/proc/<PID>/exe 符号链接以验证它是否指向您的可执行文件,而不是仅仅假设 PID 没有被回收。
【讨论】:
您可以使用文件和文件锁来完成此操作,但请注意它并不完美,不要复制臭名昭著的 Firefox 错误,即使它尚未运行,有时也会拒绝启动。
它的基本逻辑是:
Invariant:
File xxxxx will exist if and only if the program is running, and the
contents of the file will contain the PID of that program.
On startup:
If file xxxxx exists:
If there is a process with the PID contained in the file:
Assume there is some instance of the program, and exit
Else:
Assume that the program terminated abnormally, and
overwrite file xxxx with the PID of this program
Else:
Create file xxxx, and save the current PID to that file.
On termination (typically registered via atexit):
Delete file xxxxx
除了上述逻辑之外,您还应该使用您锁定的第二个文件,以同步对 PID 文件的访问(即充当互斥锁以使其在进程级并发方面安全)。
【讨论】: