Pro
Pro

Reputation: 173

How can I terminate the program when I am not waiting for the child process in the parent?

I am trying to make a program that mimics a Linux shell.

And it runs in two modes

(1) Interactive Mode (No arguments)

Wait for the child process. Execute one command at a time.

(2) Batch Mode (Given A file)

Do not wait. Try to execute the commands in parallel.

My code is pretty long so I decided to make a sample program to address (focus) on the problem that I am facing.

#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;
}

As you can see I am commenting out the wait so that I try to do concurrent processing and the results of the commands are randomized and maybe intermixed.

The problem is after the execution of the three commands date,pwd,cal

The program doesn't terminate. It freezes in this state and doesn't just end, so my cursor is there as if it needs input. And my program doesn't end. How can I fix this?

Should I use kill or what?

Upvotes: 1

Views: 413

Answers (2)

b4hand
b4hand

Reputation: 9770

You must call wait for the child processes to terminate cleanly. You don't have to call wait immediately, but you must call wait before the program ends otherwise you have zombie child processes. This works for me and still runs all of the programs in parallel:

#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;
}

The other option is to ignore the SIGCHLD signal:

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

Upvotes: 0

Some programmer dude
Some programmer dude

Reputation: 409216

Just press the Enter key after the output.

If the parent process exits before the child processes then the shell will print the prompt after the parent process exits, then the child processes prints their output but the shell won't print a new prompt. Look a few lines above the end of the output to see the prompt after the parent process exits.

For example, after modifying your code to add a sleep(1) before calling execvp (to force the child processes to be delayed) I get the following output on my system:

[~/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                 

As you see the prompt is printed before the date command runs (the .[~/tmp]$ before the date output). Pressing the Enter brings the prompt back.

Upvotes: 1

Related Questions