从C ++程序启动可执行程序&继续

时间:2013-06-25 15:17:45

标签: c++

我有一个用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”。我最初离开这篇文章是为了避免使解释复杂化,但我现在看到包含它是不完美的。

1 个答案:

答案 0 :(得分:7)

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

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

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

当你正确分叉时(就像在你的例子中那样),你现在有两个进程,而且没有一个正在等待另一个进程 - 它们只是在完全不同的代码路径中运行。你基本上想要的是让父母什么也不做,只是坐在那里等待新节目开放,偶尔检查孩子们的状态,而孩子们只要他们想要就跑步和玩耍。

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

如果您的状态不如您提出的问题简单,您将需要在分叉和执行后查看管道。否则,您只需要进行过程监控。

根据您的 EDIT 2 ,您仍然在流程管理领域,而不是IPC。 kill命令向进程发送信号(如果命令为非0)。你要找的是拥有父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();,现在孩子知道父母。)信号没有数据,它们只是非常原始的事件,但到目前为止,这听起来像你所有'寻找。