【问题标题】:Preventing multiple process instances on Linux防止 Linux 上的多个进程实例
【发布时间】:2011-02-27 05:00:02
【问题描述】:

在 Linux 平台上,进程(C++ 应用程序)检查其实例尚未运行的最佳方法是什么?

【问题讨论】:

    标签: c++ linux process


    【解决方案1】:

    执行此操作的标准方法是在某处创建一个 pidfile,通常包含程序的 pid。

    你不需要把pid放在那里,你可以在它上面放一个排他锁。如果您打开它进行读/写并使用 LOCK_EX | 聚集它LOCK_NB,如果文件已经被锁定,它将失败。这是无竞争条件的,如果程序崩溃,锁会自动释放。

    通常您希望为每个用户执行此操作,因此用户的主目录是放置文件的好地方。

    如果它是一个守护进程,像 /var/run 这样的地方会更好。

    【讨论】:

      【解决方案2】:

      对于桌面应用程序,检查是否为当前用户启动了一个实例可能更可行,以便两个用户可以运行自己的实例。

      您可以使用一些库(libunique (GTK+) 或 QtSingleApplication (Qt)),或者自己做。除了前面提到的 pid 文件之外,您还可以在用户主目录的某个位置打开 FIFO 或 UNIX 域套接字。这样,您可以与正在运行的实例进行通信,例如。提高运行实例的窗口或告诉运行实例打开新文件/URI/whatever。

      【讨论】:

        【解决方案3】:

        您可以使用POSIX named semaphore 来执行此操作。这比使用文件锁要安全得多。

        【讨论】:

        • 如何处理一个没有清理信号量就崩溃的程序?
        • 来自手册页:POSIX 命名信号量具有内核持久性:如果不被 sem_unlink() 删除,信号量将一直存在,直到系统关闭。在这里崩溃肯定是个问题。
        【解决方案4】:

        Michael 解决方案的一个相关替代方案是在已知位置(可能在 /var/run 或 /tmp 下)创建一个目录,并使用系统调用的成功/失败作为确保互斥的机制。这与 CVS 多年来使用的互斥技巧相同,因为目录创建在大多数(可能是所有)商品操作系统上都是原子的。在目录 + PID 创建进程意外死亡并且无法清理的情况下,PID 文件仍然有用。此外,在检查现有目录 + PID 是否有效时,我建议明确检查/proc/<PID>/exe 符号链接以验证它是否指向您的可执行文件,而不是仅仅假设 PID 没有被回收。

        【讨论】:

          【解决方案5】:

          您可以使用文件和文件锁来完成此操作,但请注意它并不完美,不要复制臭名昭著的 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 文件的访问(即充当互斥锁以使其在进程级并发方面安全)。

          【讨论】:

          • 使用套接字而不是文件并尝试绑定到预定义的端口不是更简单吗?而且,顺便说一句,为什么我不能在没有所有 pid 验证的情况下使用文件锁定?
          • @Jack,您可以在没有 PID 验证的情况下执行此操作,但是当程序实际崩溃并且无法清理文件时,您会冒着假设程序已打开的风险(想想 Firefox 的问题)。此外,Rakis 提出了一个很好的观点,那就是,在 Linux 上,您可以使用“/proc”中的数据来验证 PID 是否属于您的程序……有一些编程方法可以更通用地跨 UNIX 变体(至少你可以调用“ps”并解析它的输出,虽然我相信你可以调用一些函数来直接获取进程信息)。
          • 要检查进程是否存在,调用 kill(pid,0)。当进程存在时成功,否则失败。注意在不同机器上运行的进程!
          • @Jack:据 所知,您可以使用文件锁定。当程序启动时,做一个 try-lock 操作,如果成功则它是第一个实例。
          • @Jack:绑定到预定义(可能是临时)端口失败的原因有很多,而不是同一程序的另一个实例正在运行。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-02-11
          • 1970-01-01
          • 1970-01-01
          • 2011-01-11
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多