我的C类包含一个非常小的shell。
我们的shell检查用户输入行是否有内部命令(如cd或exit),如果没有找到,则forks()和execs()输入行。
我希望实现一个万无一失的分叉(这是超出本课的职责范围,请不要让我做自己的功课,这更多的是个人研究,以了解更多的Linux '内部)。 我目前的做法是:
t = fork();
if (t < 0) {
if (errno == ENOSYS) {
printf("fork() is not supported on this platform. Minishell will not work.");
break;
}
else if (errno == ENOMEM) {
printf("No free kernel memory. Minishell will exit.");
break;
}
else {
int try = 0;
while (t < 0 && try < 10) {
try++;
t = fork();
}
}
continue;
}
我的理解是ENOSYS不允许分叉,因此我们退出,ENOMEM表示内核内存故障 - 超过我的报酬(我没有报酬,我是学生;)),因此我们也退出。 保持EAGAIN有两种风格,这两种风格都可以通过等待和再次调用fork()来解决。
在之前的练习中,我们发起了一万个叉子,如果我没记错的话,大约1500个失败了,直到我们实现了一个类似于我的计数器。如果我想以一种不那么天真的方式实现这个东西,我该怎么办?特别是硬编码的十次尝试有点愚蠢,我想。
感谢。
答案 0 :(得分:5)
我认为您当前的重试方法是误解了fork的EAGAIN错误的含义。从Linux手册页:
EAGAIN fork()无法分配足够的内存来复制父页面表并为子节点分配任务结构。
EAGAIN 由于遇到调用者的RLIMIT_NPROC资源限制,因此无法创建新进程。要超过此限制,进程必须具有CAP_SYS_ADMIN或CAP_SYS_RESOURCE功能。
第一个与ENOMEM相当,第二个是达到流程上限的问题。除非你期望你的minishell让孩子一直处于死亡状态,否则连续尝试10次可能无能为力。
我建议将EAGAIN设为您的fork代码的致命错误。
但是,如果你的程序可以做些什么来减轻内存压力(释放你的程序缓存等),你可以这样做并再试一次。
值得一提的是,在正常负载下,任何现代系统几乎都不存在导致fork失败的条件。
答案 1 :(得分:2)
EAGAIN
表示您有太多进程/子进程。
如果子命令是相当短暂的,那么wait
的方法可以使其中一个命令退出。但是如果你的资源(进程或内存)由于其他进程而不是你的shell的子进程,那么你运气不好。