什么决定了可执行文件是否可以同时在不同的独立进程中运行?

什么决定了可执行文件是否可以同时在不同的独立进程中运行?

我已经发布一个问题关于如何在wine下在多个进程中独立运行一个可执行文件(一个PDF查看器)(独立意味着它们之间没有通信,它不是并行计算)。我听说有些公司的PDF编辑器(查看器的增强版)不能做到这一点。

问题

  • 所以我想知道是什么使得可执行文件能够或不能在多个进程中独立运行?
  • 它是由程序本身或某些库实现的吗?
  • 操作系统不能实现这一点吗?

答案1

这几乎肯定是由程序本身实现的,并且操作系统可能不可能强制执行除了最基本的程序之外的所有程序。

但是,如果您知道程序确定其已在运行的方式,并且该方式是您可以影响的,那么您确实可以获得可执行文件来启动新进程(或不启动新进程)。

有些应用程序使这变得特别容易,例如 Emacs。运行 Emacs 的标准方法是为每次调用启动一个新进程。但您也可以在服务器模式下显式运行 Emacs,然后emacsclient显式运行以告诉现有服务器访问新文件。

作为一个相反的示例,Firefox 提供了一个强制启动新进程的命令行选项-no-remote,而默认设置是在可能的情况下与已运行的进程进行交互。

许多简单的本土应用程序将通过简单地查询ps.这可以通过多种方式规避。工业强度软件的问题在于,用户几乎永远不知道特定应用程序如何决定它是否已在使用。即使在 Unix 上,您可以检查与可执行文件交互的所有打开文件,也不能保证您可以找出哪个文件(如果有的话)负责记录应用程序正在运行的事实。

答案2

进程是程序的一个实例。一个程序可以被实例化多次,即可以创建多个进程并加载相同的可执行代码。我想引用一句了解 Linux 内核作者:丹尼尔·P·博维 (Daniel P. Bovet) 和马可·塞萨蒂 (Marco Cesati):

区分程序和进程很重要;多个进程可以执行同一个程序同时,而同一个进程可以执行多个程序依次地

基本上,这意味着虽然程序可以跑步在某些情况下,单个实例一次只能加载一个可执行代码。所以,从那里开始,我们可以说没有什么防止程序运行到多个实例中,因为绝对没有理由禁止它。当然,这些进程除了执行代码之外不会共享任何东西。内存页、文件描述符(可能涉及相同的文件)等等......从一个进程到另一个进程完全独立。

当谈到类 Unix 系统时,另一点对我来说似乎很重要(同一本书):

类Unix操作系统采用进程/内核模型每个进程都幻想自己是机器上唯一的进程,并且它具有对操作系统服务的独占访问权。

事实上,这就是 Unix 系统具有多处理/多道程序设计的原因,或者至少,这是该功能所基于的策略。因此,由于这个事实,进程无法天生就知道运行完全相同代码的另一个进程正在等待或在另一个 CPU 上工作。

然而,每个进程都知道一件事:系统由内核运行,并且内核的服务在进程在 CPU 上工作的所有时间内都由进程使用。由于这一点,一个进程可以询问关于作为同一可执行文件的实例运行的其他进程的内核。我想到的第一个解决方案是读取/proc虚拟文件系统。该文件系统的作用就像用户/应用程序和内核之间的接口(因为这些文件代表内核结构和数据)。在此文件系统中,每个进程都有一个目录(以其 PID 命名),在该目录中,您将找到一个名为exe.例如,这是我的bash进程目录,PID 22343:

lrwxrwxrwx /proc/22343/exe -> /bin/bash*

现在,通过浏览文件系统,您将能够找到运行相同可执行代码的进程,即链接exe针对相同可执行文件的进程。

然而,由于所有 Unix 系统的实现方式并不/proc相同,开发人员的目标是使用更便携的解决方案,该解决方案依赖于几乎所有 Unix 系统都理解的东西:常规文件。这就是.pid文件通常放在这里的目的。

大多数时候,您会在/run.例如:

-rw-r--r-- /run/acpid.pid
-rw-r--r-- /run/atd.pid
-rw-r--r-- /run/crond.pid

这些文件由它们所属的应用程序创建,并用作程序实例是否正在运行的标记。通常,该文件的内容仅由正在运行的进程的 PID 组成。在本例中,我有一个acpid正在运行的进程,PID 为 1503,这正是 PID 文件中的内容。

现在,由于同一程序的所有进程共享相同的执行代码,因此它们共享它们的常量(至少是它们的值)。因此,如果每个实例都知道在哪里查找 PID 文件,那么编写单实例程序就非常容易了:

if (the pid file exists) then
    send a signal to the running process or just bring it on the foreground
    exit since the work is going to be handled by the already-running process
else
    actually start the program, the first instance
endif

在第一种情况下使用信号是我见过最多的行为,但是,如果您的应用程序使用一些更复杂的 IPC(套接字、消息队列...),您可以使用它来通知它用户已请求某些内容它需要做。

相关内容