我是C语言的初学者,但我在理解C语言中的execve
函数以调用子进程来加载和运行可执行对象文件方面感到很苦。
我们知道execve
仅在出现诸如找不到文件名之类的错误时才返回到调用程序,因此它被调用一次,永不返回。
这是我的问题,如果我们派生一个子进程来调用execve
,但是由于execve
永不返回,那么如果一切正常,它将始终执行某些操作,这意味着该子进程将永远不会执行被终止,那么父进程如何获得此子进程?下面是示例代码
if ((pid = Fork()) == 0) { /* Child runs user job */
if (execve(argv[0], argv, environ) < 0) { -------->line 2
printf("%s: Command not found.\n", argv[0]);
exit(0);
}
}
/* Parent waits for foreground job to terminate */
if (waitpid(pid, &status, 0) < 0) { ------------> but the child process never terminated
printf("waitpid error");
}
那么在第2行中,execve(argv[0], argv, environ)
永不返回,因此子进程永不终止吗?
答案 0 :(得分:1)
您的程序foo
将启动一些子进程来运行其他程序bar
,
并且您希望它使用基本系统调用fork
和execve
让我们调用您最初的foo
进程 p1 。 (这代表一些pid。)
首先,您将呼叫fork。
这样会创建 p1 的子进程,该子进程正在运行foo
的另一个实例
将该子进程称为 p1.1 。
p1.1 正在运行foo
。但是您想运行bar
。因此,在 p1.1 中,foo
立即调用execve(path/to/bar ...)
。
这将用foo
的实例替换 p1.1 正在运行的bar
的实例。那你的
子进程 p1.1 根据需要正在运行bar
。
对此有所了解:-
execve(path/to/bar ...)
不会在新的子过程中以 开始bar
p1.1 ,并使 p1.1 仍在运行foo
的后叉实例。相反,execve(path/to/bar ...)
替换
foo
实例与bar
实例在进程 p1.1 中。在fork
之后但在execve
之前,
我们有:
p1[foo] -> p1.1[foo]
在execve
之后,我们有:
p1[foo] -> p1.1[bar]
不是:
p1[foo] -> p1.1[foo] -> p1.1.1[bar]
然后您会看到execve
无法将成功返回给其调用者 p1.1 [foo],
因为如果execve
成功,则 p1.1 [foo] 不再存在。
当然,execve
无法将成功返回给 p1 [foo],因为 p1 [foo] 没有调用它。>
由于execve永不返回,如果一切正常,它将始终执行某事
不。 execve
用 p1.1 [bar]替换 p1.1 [foo],并且不返回,因为调用者不再存在。然后 p1.1 [bar]运行直到终止。
p1.1 [bar]迟早会以一种方式终止
any 程序终止:它将运行到正常的exit
为止,否则它将终止
被信号杀死,或者可能调用自己的意志abort
。
父进程( p1 )如何获得此子进程( p1.1 )?
首先,不必。一旦 p1 [foo]启动了 p1.1 ,它可以,
如果那是您想要的,就不用管 p1.1 了,继续从事其他业务
(如果有),最后是exit
。如果 p1 在 p1.1 之前终止,则 p1.1
成为orphan process。
init
process立即将孤立过程作为孩子。所以
如果在此期间没有任何终止操作,则init
终止时,系统将关闭 p1.1 。
但是很可能您不想遗弃孤儿,而您要做希望foo
知道孩子bar
的退出状态。在这种情况下,
p1 [foo]迟早必须致电wait/waitpid来学习 p1.1
结束,然后采取相应行动。
与此同时, p1 [foo]可能正在与 p1.1 [bar]进行一些通信
inter-process communication的形式。和/或 p1 [foo]可能
注意 p1.1 [bar]尚未结束的经过时间。通过其中一种或多种方式, p1 [foo]可能会确定
p1.1 [bar]遇到了麻烦,已经持续了太长时间,因此决定自行kill p1.1 。
当 p1.1 被杀死时-无论是谁-或以自己的意愿结束,wait/waitpid
都会将该信息返回给 p1 [foo],然后
可能退出自身,或继续做其他事情。
在您要求的评论中:
我们是否不能像[
execve
那样设计:如果子进程终止,则返回1?
这样的系统调用当然可以设计并且已经存在,但是它不能
是代替呼叫过程的非阻塞系统调用,即execve
是。这将是一个阻塞系统调用,它将运行该调用的子过程
进程,并将子进程的退出状态返回给父进程。这样的人就是system
答案 1 :(得分:0)
答案 2 :(得分:0)
在简单的情况下,无论您是否成功调用exec
,子进程都会最终终止。因此,这很容易……只要使用wait
创建的每个孩子都有一个父亲fork
。
但是,有一种技术可以将故障从exec
传播到父级。该技术的工作原理如下:
exec
。如果失败,则将失败消息写入管道,然后退出。 如果exec
成功,则父进程将不读取任何数据,而仅获得EOF。如果失败,则父级将读取错误消息。