For some reason this code executes the parental commands immediately, terminating my semaphores and screwing up my flow control of other programs. Can anyone tell me why the waitpid() isnt working?
//Create child processes
pid = fork();
if(pid < 0){
fprintf(stderr, "Fork Failed.\n");
exit(1);
return;
}else if(pid==0){
if(execl("/home/tropix/hw11-2","/home/tropix/hw11-2",semarg,pipe_to_p3,pipe_to_p4,(char*)0)){
fprintf(stderr, "File Exexecution of hw11-2 failed.\n");
exit(1);
}
} else {
pid = fork();
if(pid < 0){
fprintf(stderr, "Fork Failed.\n");
exit(1);
return;
} else if(pid==0){
if(execl("/home/tropix/hw11-3","/home/tropix/hw11-3",shmarg,semarg,pipe_from_p2,pipe_to_p5_1, (char*)0)){
fprintf(stderr, "File Execution of hw11-3 failed.\n");
exit(1);
}
} else {
pid = fork();
if(pid < 0){
fprintf(stderr, "Fork Failed.\n");
exit(1);
return;
} else if (pid == 0){
if(execl("/home/tropix/hw11-4","/home/tropix/hw11-4",shmarg,semarg,pipe_from_p2_2,pipe_to_p5_2, (char*)0)){
fprintf(stderr, "File Execution of hw11-4 failed.\n");
exit(1);
}
} else {
pid = fork();
if(pid < 0){
fprintf(stderr, "Fork Failed.\n");
exit(1);
return;
} else if (pid == 0){
if(execl("/home/tropix/hw11-5","/home/tropix/hw11-5",semarg,pipe_from_p3,pipe_from_p4,(char*)0)){
fprintf(stderr, "File Execution of hw11-5 failed.\n");
exit(1);
}
} else if (pid > 0) {
}
}
}
//Closing Pipes
close(pipe1[1]);
close(pipe2[1]);
close(pipe3[1]);
close(pipe4[1]);
close(pipe1[0]);
close(pipe2[0]);
close(pipe3[0]);
close(pipe4[0]);
//Wait for child process completetion
waitpid(pid,NULL,0);
printf("Child Processes Complete.\n");
//Terminate Semaphores
semctl(sem_id,0,IPC_RMID);
//Terminate Shared Memory Segement
shmctl(shmid, IPC_RMID, NULL);
}
}
Thanks!
EDIT: Ok, I replaced waitpid with:
while (pid = waitpid(-1, NULL, 0)) {
if (errno == ECHILD) {
break;
}
}
and that got me part of the way there. It isnt executing the parental controls immediately, but it seems to never execute now. As far as the pipe issue you talked about, program 1 (this one) is supposed to terminate all IPC elements, including the pipes. If there is a better way, I would love to hear it.
Thanks @Jonathan
You only wait for one process to complete – not for all processes to complete. That is probably one problem. Fix with a loop on
waitpid()until it returns ‘no more kids’.The structure of the code leaves something to be desired – it is a rabbit’s warren of nested if’s; ick!
I worry that you are not closing enough pipes before the other commands are executed. You may be OK if the commands do not depend on detecting EOF on a pipe; otherwise, you are in for a long wait.
You need a function like:
This simplifies your error handling. You can also do things like automatically add the PID that is dying, or the error that triggered the exit, if you wish.
We can also create a function to run another command:
With those in place, we can look to reduce your code to this…
Hmmm…some of these have the
shmargand some don’t – is that inconsistency intentional or accidental? We’ll assume intentional, so we need two versions of ‘run_command()’:And then:
If it was my code, the names of the variables would be more uniform – and probably in arrays:
Then, finally, you have the code:
I am deeply suspicious that the
run_cmdX()functions also need to close a large selection of the pipes – at least every descriptor of the pipes not intended for communication with their sub-process.Organizing that cleanly is trickier – but can be done with care. I’d probably create the pipes in a single array:
Then I’d create a function:
Then it can be called to close the unneeded pipes:
You just have to arrange for the right mask to be passed with each of the
run_cmdN()functions, and the correct calls to be made. If thepipesarray is not global, that will need to be passed too. I’d also look at how to encode the data tidily so that the calls torun_cmdN()are as regular and symmetric as possible.Kernighan & Plauger’s “The Elements of Programming Style” (2nd Edn, 1978; hard to find, I suspect) contains many magnificent quotes. The immediately apposite one is (bold emphasis added, italics in original):
This can be viewed as part of the DRY (Don’t Repeat Yourself) principle of programming. The
err_exit()function call encapsulates three or four lines of code – a print and an exit plus the braces, depending on your preferred layout. Therun_command()functions are a prime case of DRY. The proposedpipe_closer()is yet another.