当我不等待父进程中的子进程时,如何终止程序?

时间:2016-02-09 17:39:40

标签: c fork wait kill execvp

我正在尝试制作一个模仿Linux shell的程序。

它以两种模式运行

(1)交互模式(无参数)

等待子进程。一次执行一个命令。

(2)批处理模式(给定文件)

不要等。尝试并行执行命令。

我的代码很长,所以我决定制作一个示例程序来解决(关注)我所面临的问题。

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdlib.h>

struct commands
{
    char *cmd[2];
};

int main(int argc, char *argv[])
{
    printf("A program made to understand execvp\n");

    commands threeCommands[3];

    pid_t process;
    int child_status;

    threeCommands[0].cmd[0] = "date";
    threeCommands[0].cmd[1] =  NULL;

    threeCommands[1].cmd[0] = "pwd";
    threeCommands[1].cmd[1] =  NULL;

    threeCommands[2].cmd[0] = "cal";
    threeCommands[2].cmd[1] =  NULL;

    for(int i = 0;i <3;i++)
    {
        process = fork();

        if(process == 0)
        {
            execvp(threeCommands[i].cmd[0],threeCommands[i].cmd);
        }
        else
        {
             //wait(&child_status);
        }
    }

    return 0;
}

正如你所看到的,我正在评论等待,以便我尝试进行并发处理,并且命令的结果是随机的,也许是混合的。

问题出在执行三个命令date,pwd,cal

之后

该程序没有终止。它在这种状态下冻结并且不会结束,所以我的光标就像它需要输入一样。而我的计划并没有结束。我该如何解决这个问题?

我应该使用kill还是什么?

2 个答案:

答案 0 :(得分:1)

输出后只需按 Enter 键即可。

如果父进程在子进程之前退出,那么shell将在父进程退出后打印提示,然后子进程打印输出,但shell不会打印新的提示。查看输出结尾上方的几行,以在父进程退出后查看提示。

例如,在修改代码以在调用sleep(1)之前添加execvp(以强制延迟子进程)之后,我在系统上得到以下输出:

[~/tmp]$ ./a.out 
A program made to understand execvp
[~/tmp]$ tis  9 feb 2016 18:54:06 CET
/home/XXXX/tmp
   Februari 2016      
sö må ti on to fr lö  
    1  2  3  4  5  6  
 7  8  9 10 11 12 13  
14 15 16 17 18 19 20  
21 22 23 24 25 26 27  
28 29                 

如您所见,在date命令运行之前打印提示(.[~/tmp]$输出之前的date。按 Enter 会返回提示。

答案 1 :(得分:0)

您必须调用wait才能使子进程干净地终止。您不必立即致电wait,但必须在程序结束前致电wait,否则您将拥有僵尸子进程。这对我有用,并且仍然并行运行所有程序:

#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

struct commands
{
    char *cmd[2];
};

int main(int argc, char *argv[])
{
    printf("A program made to understand execvp\n");

    struct commands threeCommands[3];

    pid_t process;
    int child_status;

    threeCommands[0].cmd[0] = "date";
    threeCommands[0].cmd[1] =  NULL;

    threeCommands[1].cmd[0] = "pwd";
    threeCommands[1].cmd[1] =  NULL;

    threeCommands[2].cmd[0] = "cal";
    threeCommands[2].cmd[1] =  NULL;

    for(int i = 0;i <3;i++)
    {
        process = fork();

        if(process == 0)
        {
            execvp(threeCommands[i].cmd[0],threeCommands[i].cmd);
        }
    }

    for(int i = 0;i <3;i++)
    {
        wait(&child_status);
    }

    return 0;
}

另一种选择是忽略SIGCHLD信号:

signal(SIGCHLD, SIG_IGN); // automatically reap child processes