万无一失的分叉?

时间:2013-11-08 15:21:26

标签: c fork

我的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个失败了,直到我们实现了一个类似于我的计数器。如果我想以一种不那么天真的方式实现这个东西,我该怎么办?特别是硬编码的十次尝试有点愚蠢,我想。

感谢。

2 个答案:

答案 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的子进程,那么你运气不好。