2

我有一个用 C++ 编写的程序,旨在在 Linux 操作系统上运行。忽略程序的大部分内容,归结为 - 它在一段时间后启动 X 个可执行文件(为简单起见,让我们使用 5 秒)。

目前,我正在使用system(path/to/executable/executable_name)执行可执行文件的实际启动,这对于启动可执行文件来说效果很好。

我还试图维护每个可执行文件的状态(再次简单起见,我们只是说状态是“UP”或“DOWN”(运行或未运行))。我已经能够做到这一点......有点......

稍微备份一下,当我的程序被告知启动可执行文件时,逻辑如下所示:

pid = fork()
if (pid < 0) exit 0; //fork failed
if (pid == 0) {
   system(path/to/executable/executable_name)
   set executable's status to DOWN
} else {
   verify executable started
   set executable's status to UP
}

这就是我的问题。fork()导致产生一个子进程,这是我认为我需要的,以便原始进程继续启动其他可执行文件。我不想等待可执行文件停止以启动另一个。

但是,可执行文件在另一个子进程中启动......它与父进程分开......如果我在系统返回时尝试在子进程中将可执行文件的状态设置为 DOWN,则父进程不知道它。 ..

我对我可能需要做的事情有一些想法:

  • 使用线程而不是 fork:创建一个新线程来调用系统,但是父/主线程会知道新线程会改变可执行文件的状态吗?
  • 使用 fork 和 exec:但我不确定这会比我已经拥有的更好(我已经阅读了 fork 和 exec 的手册页,但我想我对如何最好地利用 exec 仍然有点模糊)

有什么建议么?

编辑 1 我想我最好为逻辑提供更多背景信息:

void startAll() {
    for each 'executable'
    call startExecutable(executable_name)
}

...

void startExecutable (executable_name) {
    pid = fork()
    if (pid < 0) exit 0; //fork failed
    if (pid == 0) {
        system(path/to/executable/executable_name)
        set executable's status to DOWN
        exit (1); <-- this is because once the child process's system returns, I don't want it to return to the above loop and start starting executables
    } else {
        verify executable started
        set executable's status to UP
    }
}

编辑 2 如开头所述,这是假设一个简化的设置(如果你愿意,第一次运行)。该计划不仅要处理“UP”或“DOWN”状态,还要处理向我的程序已启动的可执行文件发送消息的第三种状态——“STANDBY”。我最初忽略了这一部分以避免使解释复杂化,但我现在看到包含在内是必要的。

4

1 回答 1

7

您需要了解当您fork. 你正在做的是创建一个子进程,它是分叉进程的精确克隆。当前在内存中的所有变量都被精确复制,并且子进程可以访问所有这些变量的所有副本。

但是它们是副本,所以正如您所注意到的,fork 和 exec/system 本身并不处理进程间通信 (IPC)。在其中一个进程中设置内存值不会改变任何其他进程(包括其父进程)中的该变量,因为内存空间不同。

此外,system与 非常相似exec,但对文件描述符和执行环境的控制要少得多。你实际上已经在做一个 fork 和 exec,这是你应该做的。

当您正确分叉时(就像您在示例中所做的那样),您现在有两个进程,并且没有一个进程在等待另一个进程 - 它们只是在完全不同的代码路径中运行。您基本上想要的是让父母什么也不做,只是坐在那里等待新程序打开,偶尔检查孩子的状态,而孩子们可以随心所欲地奔跑和玩耍。

有 IPC 解决方案,例如管道和消息 FIFO 队列,但在您的情况下这太过分了。就您而言,您只是在寻找流程管理。父母被赋予孩子的pid。保存并使用它。您可以打电话waitpid等待孩子结束,但您不希望这样。您只希望父母检查孩子的状态。一种方法是检查if kill(childPid,0) == 0。如果不是,则 pid 已退出,即它不再运行。您还可以检查/proc/childPid各种信息。

如果您的状态不如您的问题所暗示的那么简单,那么您需要在分叉和执行后查看管道。否则,您所需要的只是过程监控。

根据您的EDIT 2,您仍处于流程管理领域,而不是 IPC。该kill命令向进程发送信号(如果该命令为非 0)。您正在寻找的是拥有 parent kill(childPid, SIGTSTP)。在孩子方面,您只需要使用signal命令制作一个信号处理程序。在许多其他参考资料中,请参阅http://www.yolinux.com/TUTORIALS/C++Signals.html。基本上,你想要:

void sigTempStopHandler(int signum) { /* ... */ }
signal(SIGTSTP, sigTempStopHandler);

在子代码中执行。当然,父母会知道何时发送此状态,因此可以更改状态。您可以在必要时使用其他信号进行恢复。

何时管道与信号:

管道是您可以使用的最强大的 IPC - 它允许您将任意数量的数据从一个进程发送到另一个进程,并且可以发送到您想要的任何方向。如果您希望您的父母向孩子发送“你一直是个非常坏的男孩”,它可以,并且孩子可以向父母发送“但我有一天会选择您的疗养院”。(不那么轻率,您可以将任何数据,无论是文本还是二进制文件从一个进程传递到另一个进程 - 包括您序列化的对象,或者如果它不依赖于内存,则只是对象的原始数据,例如 int。)

到目前为止,您所描述的是从父级向子级发送简单的命令结构,并且kill非常适合。孩子几乎可以很容易地发送信号——只是它需要知道父母的 pid 才能做到这一点。(不难做到 - 在分叉之前,保存 pid: int pid = getPid();,现在孩子知道父母。)信号没有数据,它们只是非常原始的事件,但到目前为止,这听起来就像你正在寻找的一切。

于 2013-06-25T15:42:59.280 回答