我有一个用 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”。我最初将这部分内容排除在外是为了避免使解释复杂化,但现在我发现必须包含它。
最佳答案
您需要了解当您fork
时到底发生了什么。您正在做的是创建一个子流程,它是 fork 流程的精确克隆。当前内存中的所有变量都被精确复制,子进程可以访问所有这些变量的所有拷贝。
但它们是拷贝,因此正如您所注意到的,fork 和 exec/system 本身并不处理进程间通信 (IPC)。在其中一个进程中设置内存值不会改变任何其他进程(包括其父进程)中的该变量,因为内存空间不同。
此外,system
与exec
非常相似,但您对文件描述符和执行环境的控制要少得多。您实际上已经在进行 fork 和 exec,这是您应该做的。
当您正确地 fork 时(就像您在示例中所做的那样),您现在有两个进程,并且没有一个在等待另一个 - 它们只是在完全不同的代码路径中运行。您基本上想要的是让 parent 什么也不做,只是坐在那里等待新程序打开,偶尔检查 child 的状态,而 children 想跑就跑,想玩就玩。
有 IPC 解决方案,例如管道和消息 FIFO 队列,但在您的情况下这太过分了。就您而言,您只是在寻找流程管理。 parent 被赋予 child 的pid。保存并使用它。您可以调用 waitpid
来等待子进程结束,但您不希望这样。您只希望 parent 检查 child 的状态。一种方法是检查 if kill(childPid,0) == 0
。如果不是,那么 pid 已经退出,即它不再运行。您还可以检查 /proc/childPid
以获取各种信息。
如果您的状态没有您的问题所暗示的那么简单,您将需要在 fork 和 execing 之后查看管道。否则,您所需要的只是过程监控。
根据您的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 - 它允许您将任意数量的数据从一个进程发送到另一个进程,并且可以按您想要的方向发送。如果你想让你的 parent 把“你一直是个很坏的 child ”发给 child ,可以, child 也可以发给 parent “但总有一天我会选择你的养老院”。 (更简单地说,您可以将任何数据,无论是文本还是二进制数据从一个进程传递到另一个进程 - 包括您序列化的对象,或者如果它不依赖于内存,则只传递对象的原始数据,例如 int。)
到目前为止,您所描述的是将简单的命令结构从父级发送到子级,kill
非常适合此操作。 child 几乎可以很容易地发送信号——除了它需要知道 parent 的 pid 才能做到这一点。 (不难做到 - 在 fork 之前,保存 pid:int pid = getPid();
,现在子知道父。)信号没有数据,它们只是非常原始的事件,但是到目前为止,这听起来就是您要查找的全部内容。
关于c++ - 从 C++ 程序启动可执行文件并继续,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17301181/