My program does not stop running after finishing child process - c

I am now learning about folk, exec etc and I have this piece of code:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
pid_t childpid;
int status;
childpid=fork();
if (childpid== -1){
perror("Failed to fork\n");
exit(1);
}
if (childpid==0) {
printf("I am in child process with id = %lu\n", (long)getpid());
execvp(argv[1], &argv[1]);
perror("exec failure ");
exit(1);
}
else {
printf("I am in parent process with id = %lu\n", (long)getpid());
exit(1);
}
}
The child process works fine but after that for some reason the program continues running without doing anything. It never prints "I am in child process with id = ...." or "I am in parent process with id =... ". It's like it never goes to parent process. Do you have any ideas why? Thanks in advance

From my top comment ...
You are creating a zombie process. This is because the parent process is not waiting for the child to complete.
The parent process will terminate [relatively] quickly. Thus, the child loses its parent and becomes a zombie. A zombie will be reparented by the kernel as a child of process 1 (e.g. systemd or initd).
To fix, add: wait(NULL); after the final printf
UPDATE:
Therefore do I need to always put wait(NULL) in these types of situations?
The TL;DR is ... Yes!
This is what you normally want to do for most programs.
One of the few times you would want to create a zombie is (e.g.) if you're a server program (e.g. inetd).
Servers want to run "detached". That is, as a child of the init process (e.g. systemd, initd, etc.). There is one and only one init process on the system.
All other processes are children of init, even if indirectly. For example, your program's process hierarchy was something like:
init -> window_manager -> xterm -> bash -> your_program
Anyway, most server programs these days are fired up by systemd directly. It examines some config files and starts things based on these config options. So, now, most server programs don't have to do anything special.
But, if you were testing a server of your own, invoked it from the command line, and wanted it to run [detached] in the background, you might do:
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <sys/wait.h>
int opt_d;
int
main(int argc, char **argv)
{
char *cp;
pid_t childpid;
int status;
// skip over program name
--argc;
++argv;
for (; argc > 0; --argc, ++argv) {
cp = *argv;
if (*cp != '-')
break;
cp += 2;
switch (cp[-1]) {
case 'd':
opt_d = 1;
break;
}
}
// detach into background
if (opt_d) {
childpid = fork();
if (childpid == -1) {
perror("Failed to detach\n");
exit(1);
}
// exit the parent -- child is now detached [and a zombie] and a child
// of the init process
if (childpid != 0)
exit(0);
}
childpid = fork();
if (childpid == -1) {
perror("Failed to fork\n");
exit(1);
}
if (childpid == 0) {
printf("I am in child process with id = %lu\n", (long) getpid());
execvp(*argv, argv);
perror("exec failure ");
exit(1);
}
printf("I am in parent process with id = %lu\n", (long) getpid());
wait(&status);
return 0;
}

Related

Fork and exec several children in linux

I want to fork and exec several processes from another.
My parent code is
/*Daddy.c*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int main(void)
{
int status;
char *nChild;
for (int i=0; i<3;i++){
int pid = fork();
if (pid == 0)
{
sprintf(nChild, "%d", i);
printf("%d\n", i);
char *const arguments[]={nChild, NULL};
fflush(NULL);
execv("child",arguments);
printf("\nNo , you can't print!\n");
}else if (pid == -1){
printf("%d\n", getpid());
exit(0);
}
}
wait(&status);
printf("Dad %d went out!\n", getpid());
exit(0);
}
and my child process is
/*child.c*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int args, char **argv){
if( args !=2){
printf("Child going away!\n");
exit(1);
}
printf("Child %s: %d going away stylishly!\n", argv[1], getpid());
exit(0);
}
When I don´t create three forks, but one, I know how to create the child, do some work and exit from child and parent. But, in this case, with several children it seems like the child never executes.
Because of the line wait(&status) I did hope that when the first child exits, the parent also exits but, any child prints any message.
Some relevant previous questions didn´t help.
You need to make parent wait for all child processes to finish. If not, assume that 1 child waited for is done and then parent exits. What about the other 2 children? They become orphan since their parent doesn't wait for them.
pid_t wpid;
int status = 0;
.
.
while ((wpid = wait(&status)) > 0); // the parent waits for all the child processes
This code did the job
/* daddy.c */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <string.h>
int main(void)
{
int status=0;
char nChild[16];
pid_t wpid;
for (int i=0; i<3;i++){
sprintf(nChild, "%d", i);
int pid = fork();
if (pid == 0)
{
printf("%s\n", nChild);
char *const arguments[]={"child", nChild, NULL};
fflush(NULL);
execv("child",arguments);
printf("\nNo , you can't print!\n");
}else if (pid == -1){
printf("%d\n", getpid());
exit(0);
}
}
while ((wpid=wait(&status)) >0);
printf("Dad %d went out!\n", getpid());
exit(0);
}
As #OnzOg said in the comments of the question, allocation of nChild was the main problem. Also execv need pass child name twice, one as argument.
And finally, to improve the code, parent process needs to wait all processes to finish.

How to set status termination of a process C?

My program is a rudimental little shell.
It allow you to run programs in PATH as ls, cd..also with arguments.
To run the program type from terminal "./myshell2" then it starts and you can insert how many commands you want.
It starts a child process, runs execvp,it returns and restarts so you can type a new command.
When typed "Q" or "q" all the entire program should terminates.
The problem is that I don't know how to stop it,the code is below.
My idea is, when typed "Q" or "q", to kill the child process created and send a signal to comunicate its bad termination(of child process).
So the final status(from parent) 'll be not 1 and the function returns.
I commented some parts of the code hoping that it's easier to understand.
It works the problem is that to stop it I need of ctrl C.
I would like to say to child process that he must ends with a non-zero value.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <string.h>
#include <signal.h>
int main(int argc, char * argv[]) {
while(1)
{
pid_t pid = fork();
if (pid == -1) {
perror("fork error");
exit(EXIT_FAILURE);
}
if (pid == 0) { // child process
printf("type the command to start (and arguments if required) \n"
"Q to quit\n");
char *dest[10]; // allow you to insert
char line[4096];//commands from terminal
if (fgets(line,sizeof(line),stdin)==0) return 1;
int i;
line[strcspn(line, "\n")] = '\0';
char *st = line;
for (i=0; i< 10 && (dest[i]=strsep(&st," "))!=NULL;i++)
continue;//now you typed the command
if ( ( memcmp(dest[0],"Q",1)==0 ) // if Q or q the program
|| (memcmp(dest[0],"q",1)==0) ) //must end
{
printf("got it!\n");
if (kill(getpid(),SIGSEGV)==-1) printf("kill error\n");
//in theory the process should terminates with bad status
// and the value of the variable "status" 'll be not 0
// I think that the problem is in this part of the code
}
if( strcmp(dest[0]," ")!=0 )
{
int res = execvp(dest[0], dest);
}
else
{ int res= execvp(dest[1],dest+1);}
perror("execvp error");
exit(EXIT_FAILURE);
}
int status;
pid_t child = wait(&status);
if (child == -1) {
perror("wait error");
exit(EXIT_FAILURE);
}
if (status==1)
break; //so it can exit from the loop that creates new process
setenv("WAIT","TRUE",0); //dont' worry about
//perror("setenv error\n");
if (memcmp("TRUE",getenv("WAIT"),4) == 0 ) //these 6 lines
printf("WAIT=TRUE\n");
else if(memcmp("FALSE",getenv("WAIT"),4) == 0 )
printf("WAIT=FALSE\n");
printf("end current process (status=%d, child=%d)\n", WEXITSTATUS(status), son);
}
return EXIT_SUCCESS;
}
You're printing out WEXITSTATUS() for all cases, but that isn't right. You need to check if the status returned by wait is an exit status or not using WIFEXITED(). If it's non-zero then the child exited normally. Otherwise, you can use WIFSIGNALED() to see if the child was terminated and you'll get the signal from WTERMSIG()
if(WIFEXITED(status))
{
printf("end current process (status=%d, child=%d)\n", WEXITSTATUS(status), son);
}
else if(WIFSIGNALED(status))
{
printf("end current process (signal=%d, child=%d)\n", WTERMSIG(status), son);
}
You really should have the parent process handle the inputting of the command and leave the child process to run it though.

C program that tells the user which child process finished first

I am working on an assignment that involves using fork. The program runs two separate programs simultaneously and tells the user which one finished first. If a child finishes, the other child still running should be killed immediately.
My code so far is this...
int main(int argc, char **argv) {
if (argc != 2) {
perror("Invalid number of arguments!");
exit(1);
}
pid_t pid;
pid_t wpid;
int status = 0;
for (int i = 0; i < 2; i++) {
if ((pid = fork()) == 0) {
execv("/bin/sh", argv[i+1]);
}
}
while ((wpid = wait(&status)) > 0);
printf("%s finished first!", <Insert winning program here>);
return 0;
}
From my understanding, this runs the programs and will not let the parent process continue until the child processes have finished. Now I'm wondering how I can terminate another child and return the winning process.
But how can I immediately get the pid of the losing process so that I can kill it?
Just as TonyB told: the "parent" saves the pid of the new child. 2) wait will tell you the pid of the winning process. More verbose: Save the PID of both children, wait for any one, compare the return value to (one of) the saved PIDs; the matching one is the winner, the non-matching one is the loser. E. g.:
#define _POSIX_SOURCE
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
int main(int argc, char **argv)
{
if (argc != 3) // with two program arguments, argc is 3
fputs("Invalid number of arguments!\n", stderr), exit(EXIT_FAILURE);
pid_t pid[2]; // to store both child pids
pid_t wpid;
for (int i = 0; i < 2; i++)
if ((pid[i] = fork()) == 0)
execl("/bin/sh", "sh", "-c", argv[i+1], NULL),
perror(argv[i+1]), exit(EXIT_FAILURE);
wpid = wait(NULL); // wait for first
int wi = wpid==pid[0] ? 0 : 1; // get index of winner
kill(pid[!wi], SIGKILL), wait(NULL); // kill and reap loser
printf("%s finished first!\n", argv[wi+1]);
return 0;
}

Calling every child process at once to kill?

I have to write an program which will generate a random amount of processes, and then will kill them one after one, after they all were created.
My problem is that I can't stop the child processes after being created.
Also, I try to call the termination-output to stdout from a child process, but don't really know how to solve it (because pid = 0 is for every child process).
#define _POSIX_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <time.h>
#include <signal.h>
#include <sys/wait.h>
int main(int argc, char const *argv[])
{
//int status;
srand(time(NULL));
int amount = (rand())%9+1;
pid_t fatherid = getpid();
printf("Hello I am a parent process, my PID is %d and I will now create %d children.\n",fatherid,amount);
pid_t pid = 1;
pid_t pidarr[amount];
for(int i = 0;i<amount;i++){
if(pid != 0){
pid = fork();
pidarr[i] = pid;
if(pid ==0){
printf("Hello I am a child process, my PID is %d and my parent has the PID %d.\n",getpid(),fatherid);
}
sleep(1);
}
}
if(pid != 0){
wait(NULL);
}
for(int i = (amount-1);i >= 0;i--){
if(pidarr[(i-1)] != 0){
printf("Hello I am a child process %d, I will terminate now.\n",getpid());
}
sleep(rand()%4);
if(pid != 0){
kill(pidarr[i],SIGKILL);
printf("Child Process %d was terminated.\n",pidarr[i]);
}
}
if(pid != 0){
printf("All child processes were terminated. I will terminate myself now.\n");
}
return EXIT_SUCCESS;
}
the following code shows how to handle fork and child processes.
the code compiles cleanly, is tested and works
#define _POSIX_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <time.h>
#include <signal.h>
#include <sys/wait.h>
int main( void )
{
//int status;
srand(time(NULL));
int amount = (rand())%9+1;
pid_t fatherid = getpid();
printf("Hello I am a parent process, my PID is %d and I will now create %d children.\n",fatherid,amount);
pid_t pid;
pid_t pidarr[amount];
for(int i = 0;i<amount;i++)
{
pid = fork();
if( -1 == pid )
{ //then, fork() error
perror( "fork() failed" );
exit(1);
}
// implied else, fork() successful
//pidarr[i] = pid;
if(!pid )
{ // then child process
printf("Hello I am a child process, my PID is %d and my parent has the PID %d.\n",getpid(),fatherid);
exit(0); // exit child process
}
// implied else, parent process
pidarr[i] = pid;
sleep(1);
} // end for
for(int i = (amount-1); i >= 0; i--)
{
kill(pidarr[i],SIGKILL);
printf("Child Process %d was terminated.\n",pidarr[i]);
}
printf("All child processes were terminated. I will terminate myself now.\n");
return(0);
} // end function: main
I am not sure about other parts of your logic (e.g. the if clause inside the fork loop), but
if(pid != 0){
wait(NULL);
}
looks suspiciously as of the parent process waits for a child to exit so that it doesn't get to the code which would kill the children at all (unless they exit on their own, but then the killing seems pointless).
Some issues in your code:
1) As #Peter Schneider points out,
parent process waits for a child to exit so that it doesn't get to the code which would kill the children
So first of all, you have to get rid of:
if(pid != 0){
wait(NULL);
}
2) The for loop that kills the children has to be executed only by the parent process, so the if clause embraces the for:
if(pid != 0){
for(int i = (amount-1);i >= 0;i--){
kill(pidarr[i],SIGKILL);
printf("Child Process %d was terminated.\n",pidarr[i]);
}
}
3) The child processes have to wait doing something until parent kills them, so append the following else clause to the above if:
else{
while(1){
printf("I am a child process %d. Will sleep for 2 senconds\n",getpid());
sleep(2);
}
}
4) the following code makes no sense, because when children are killed they simply stop working.
if(pidarr[(i-1)] != 0){
printf("Hello I am a child process %d, I will terminate now.\n",getpid());
}
If you want children to do something when the signal from kill() gets to them, you will have to use signals.

how to create two processes from a single Parent

I know I'm going to need to use fork(), but this just creates a single child process. Do i simply call fork again from within the child process? Also, I need them to communicate through a signal or pipe, which is easier to implement and what do i need to know for doing that (functions, etc..)
To create a second process, call fork() again - either within the parent or the child (but not both!). Which you choose depends on whether you want this process to be a child of the original parent or a child of the first child process (it is usual for it to be a child of the original parent).
Communicating through a pipe is much simpler and more reliable than using signals. pipe(), close(), read(), write() and select() are the key functions here.
For example, to have the parent create two child processes, you would do something like:
pid_t child_a, child_b;
child_a = fork();
if (child_a == 0) {
/* Child A code */
} else {
child_b = fork();
if (child_b == 0) {
/* Child B code */
} else {
/* Parent Code */
}
}
Another fancy code using && operator:
pid_t c1_pid, c2_pid;
(c1_pid = fork()) && (c2_pid = fork()); // Creates two children
if (c1_pid == 0) {
/* Child 1 code goes here */
} else if (c2_pid == 0) {
/* Child 2 code goes here */
} else {
/* Parent code goes here */
}
#include <stdio.h>
#include <unistd.h>
void main(){
int pi_d ;
int pid ;
pi_d = fork();
if(pi_d == 0){
printf("Child Process B:\npid :%d\nppid:%d\n",getpid(),getppid());
}
if(pi_d > 0){
pid = fork();
if(pid > 0){
printf("\nParent Process:\npid:%d\nppid :%d\n",getpid(),getppid());
}
else if(pid == 0){
printf("Child Process A:\npid :%d\nppid:%d\n",getpid(),getppid());
}
}
}
output :
Parent Process:
pid:3648
ppid :2379
Child Process B:
pid :3649
ppid:3648
Child Process A:
pid :3650
ppid:3648
You can put the fork in a loop and generate as many child processes as you need.
I did that on a project recently.
for(nSon=0; nSon < nSonsAsked; nSon++) {
Log_Print("Setup son #%.2u ", nSon+1);
if((pid = fork()) == 0) {
/* Do child stuff init, like connect the pipes, close shared handles */
return iTMInChild(...); /* A specific function of the child work */
/* The life of the child should not go beyond that point, i.e. the loop is over
or else the child will spawn even more processes. */
}
else if(pid > 0) {
/* Father process stuff. Here I initialise an array with the pid of the forked */
/* processes, this way I can index with the number of processes.*/
pid[nSon] = pid;
}
else
return Err_Print(ERR_FORK_FAILED, "fork failed. errno=%d \"%s\"\n", errno, strerror(errno));
}
Log_Print() and Err_Print() are internal functions but quite obvious so I let them like they are.
There is one aspect with the variables that has to be explained. nSon and nSonAsked should be declared as globals not as stack variables. This way, their value persists in the forked process. This means that the nSon variable will have a different value in each of the children. This allows it to have a simpler numbering scheme than the ownpid() number.
To get it completely right, there are a lot of details to get right. You will have to set signal handlers in the father process to detect the death of a child, likewise the other way round (only possible on Linux, other Unix (at least Solaris) do not support parent death signals).
You have to be aware that open file descriptors in the father process will be also open in the child after fork and it will be the same one. This opens a lot of concurrency problems if you're not aware of it (the solution is using dup() and close() in the right places).
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{
system ("clear");
int i ;
pid_t childa,childb,childa1,childa2,childb1,childb2;
printf("\n \t \t I am the parent process with ID %d \n",getpid());
childa=fork();
if (childa == 0 )
{
printf("\nI am a child A with PID %d and my parent ID is %d\n",getpid(),getppid());
}
else
{
childb = fork();
if (childb == 0)
{
printf("\nI am Child B with ID %d and my parent ID is %d\n",getpid(),getppid());
}
else
{
sleep(1);
}
}
}
In this example they are just sleeping for a few random sec. It also has all the pid, so we can send SIGNAL to communicate... Most of the #includes are commented cause they were useless where I compiled.
#include <stdlib.h> // exit() ...
#include <stdio.h> // printf() ...
// Compile with -lrt -> cc file_name.c -lrt
//#include <fcntl.h>
//#include <sys/stat.h>
//#include <sys/types.h>
//#include <sys/wait.h> // may need this for wait()
//#include <time.h>
//#include <unistd.h> // and this one for fork()
// In the start function you can do whatever you want.
void start (const int azon) {
// For children processes
srand( time(NULL) );
unsigned t = rand()%5; // printf("%d\n", t);
sleep(t);
printf("%d. process reached the end.\n", azon);
exit(0);
}
int main() {
const int N = 5;
pid_t pids[N];
int i;
// The 'for' loop make 'N' process with 'fork()'.
// The children processes will call the start function.
// Since after fork() you will get 2 process. One Parent, and One Child
// The returning value from fork() is saved in "pids" which is an
// integer AND it is (<0) IF something went wrong.
// it is (>0) IF 'we are' in the Parent process,
// because this number is the Child process' ID (pid).
// and Last it is (==0) IF 'we are' in the Child process.
for (i = 0; i < N; i++) {
pids[i] = fork();
sleep(1);
if (pids[i] == 0) start(i+1); // ... OR you can make a switch(..)
}
// This 'for' loop in the wait(NULL) statement ONLY move on when a
// process ended, so it waits until 'N' proc ends.
for (i = 0; i < N; i++)
wait(NULL);
printf("Partent process reached the end\n");
return 0;
}
Just a little contribution, if you want to create 2 childs from the same parent you could use this code below. In which one father create 2 child processes (lazy and active).
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int main (){
pid_t lazy_child;
lazy_child = fork();
if(lazy_child == 0){ // This is the lazy child process.
printf("LAZY CHILD:%d\n", getpid());
}
else if(lazy_child > 0){ // This is the father process.
pid_t active_child = fork();
if(active_child == 0){ // This is the active child process.
printf("ACTIVE CHILD:%d\n", getpid());
}
else if(active_child > 0){ // This is the father process.
printf("FATHER:%d\n", getpid());
}
else{ // Fork doesnt work.
printf("fork error\n");
exit(1);
}
}
else{ // Fork doesnt work.
printf("fork error\n");
exit(1);
}
return 0;
}
If you run this code, you should get a similar output:
$ ./a.out
FATHER:14501
ACTIVE CHILD:14503
LAZY CHILD:14502
#include <sys/wait.h>
#include <stdio.h>
#include <unistd.h>
int main()
{
pid_t AliceID, BobID;
double n=0;
int i1 =0;
/* fork a child process */
AliceID = fork();
if (AliceID < 0) { /* error occurred */
fprintf(stderr, "Fork Failed");
return 1;
}
else if (AliceID == 0) { /* child Alice code */
for(int i=1; i<11; i++)
{n = n+i;
i1++; }
double avg1 = n/i1;
printf("From Alice: the average of 1,2, …, 10 is the-average-she-calculated");
printf(" sum = %.2f and avg = %.2f \n",n, avg1);
}
else {
BobID = fork();
if (BobID == 0) { /* Child Bob code */
printf("From Bob: I am born to print this and then die.\n");
} else { /* Parent Code */
/* parent will wait for the child to complete */
wait(NULL);
printf("From parent: AliceID is %d \n", AliceID);
printf("From parent: Bob is %d \n", BobID);
printf("Parent ID %d \n", getpid());
}
}
return 0;
}

Resources