我有一个用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,则父进程不知道关于它...
我对我可能需要做的事情有一些想法:
有什么建议吗?
编辑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”。我最初离开这篇文章是为了避免使解释复杂化,但我现在看到包含它是不完美的。
答案 0 :(得分: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)。你要找的是拥有父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();
,现在孩子知道父母。)信号没有数据,它们只是非常原始的事件,但到目前为止,这听起来像你所有'寻找。