由于某些原因,这段代码会立即执行父命令,终止我的信号量,并搞乱我对其他程序的流控制。有人能告诉我为什么waitpid()不工作吗?
//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);
}}
谢谢!
编辑: Ok,我将waitpid替换为:
while (pid = waitpid(-1, NULL, 0)) {
if (errno == ECHILD) {
break;
}
}这让我走了一段路。它不会立即执行家长控制,但现在似乎永远不会执行。就您谈到的管道问题而言,程序1(这个)应该终止所有IPC元素,包括管道。如果有更好的办法,我很想听听。
谢谢@Jonathan
发布于 2011-05-09 08:30:15
您只需等待一个进程完成,而不是所有进程都完成。这可能是一个问题。修复waitpid()上的一个循环,直到它返回“不再有孩子”。
代码的结构不尽如人意--它是一堆嵌套的if;ick!
我担心您在执行其他命令之前没有关闭足够的管道。如果命令不依赖于检测管道上的EOF,那么您可能没有问题;否则,您将等待很长时间。
您需要一个类似以下的函数:
#include <stdarg.h>
static void err_exit(const char *format, ...)
{
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end(args);
exit(EXIT_FAILURE);
}这简化了您的错误处理。如果你愿意,你也可以做一些事情,比如自动添加即将死亡的PID,或者触发退出的错误。
我们还可以创建一个函数来运行另一个命令:
static pid_t run_command(const char *cmd, const char *shmarg, const char *semarg,
const char *fdarg1, const char *fdarg2)
{
pid_t pid = fork();
if (pid < 0)
err_exit("Failed to fork\n");
else if (pid == 0)
{
execl(cmd, cmd, shmarg, semarg, fdarg1, fdarg2, (char *)0);
err_exit("Failed to exec %s\n", cmd);
}
return pid;
}有了这些,我们就可以把你的代码简化成这样……
// Create child processes
pid_t pid1 = run_command("/home/tropix/hw11-2", semarg, pipe_to_p3, pipe_to_p4);
pid_t pid2 = run_command("/home/tropix/hw11-3", shmarg, semarg, pipe_from_p2, pipe_to_p5_1);
pid_t pid3 = run_command("/home/tropix/hw11-4", shmarg, semarg, pipe_from_p2_2, pipe_to_p5_2);
pid_t pid4 = run_command("/home/tropix/hw11-5", semarg, pipe_from_p3, pipe_from_p4);其中的Hmmm...some有shmarg,而有些没有--这是故意的还是偶然的?我们假设是故意的,所以我们需要‘run_command()’的两个版本:
static pid_t run_cmd4(const char *cmd, const char *shmarg, const char *semarg,
const char *fdarg1, const char *fdarg2)
{
pid_t pid = fork();
if (pid < 0)
err_exit("Failed to fork\n");
else if (pid == 0)
{
execl(cmd, cmd, shmarg, semarg, fdarg1, fdarg2, (char *)0);
err_exit("Failed to exec %s\n", cmd);
}
return pid;
}
static pid_t run_cmd3(const char *cmd, const char *semarg,
const char *fdarg1, const char *fdarg2)
{
pid_t pid = fork();
if (pid < 0)
err_exit("Failed to fork\n");
else if (pid == 0)
{
execl(cmd, cmd, semarg, fdarg1, fdarg2, (char *)0);
err_exit("Failed to exec %s\n", cmd);
}
return pid;
}然后:
// Create child processes
pid_t pid1 = run_cmd3("/home/tropix/hw11-2", semarg, pipe_to_p3, pipe_to_p4);
pid_t pid2 = run_cmd4("/home/tropix/hw11-3", shmarg, semarg, pipe_from_p2, pipe_to_p5_1);
pid_t pid3 = run_cmd4("/home/tropix/hw11-4", shmarg, semarg, pipe_from_p2_2, pipe_to_p5_2);
pid_t pid4 = run_cmd3("/home/tropix/hw11-5", semarg, pipe_from_p3, pipe_from_p4);如果这是我的代码,变量的名称会更统一--而且可能是在数组中:
// Create child processes
pid_t pid1 = run_cmd3("/home/tropix/hw11-2", semarg, pipearg[0], pipearg[1]);
pid_t pid2 = run_cmd4("/home/tropix/hw11-3", shmarg, semarg, pipearg[2], pipearg[3]);
pid_t pid3 = run_cmd4("/home/tropix/hw11-4", shmarg, semarg, pipearg[4], pipearg[5]);
pid_t pid4 = run_cmd3("/home/tropix/hw11-5", semarg, pipearg[6], pipearg[7]);然后,最后,您就有了代码:
// 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 completion
while (waitpid(0, NULL, 0) != 0)
;
printf("Child Processes Complete.\n");
// Remove Semaphores and Shared Memory
semctl(sem_id,0,IPC_RMID);
shmctl(shmid, IPC_RMID, NULL);我非常怀疑run_cmdX()函数还需要关闭大量的管道-至少是不打算与其子进程通信的管道的每个描述符。
干净利落地组织起来比较棘手--但要小心才能做到。我可能会在单个数组中创建管道:
if (pipe(&pipes[0]) != 0 || pipe(&pipes[2]) != 0 ||
pipe(&pipes[4]) != 0 || pipe(&pipes[6]) != 0)
err_exit("Failed to create a pipe\n");然后我会创建一个函数:
void pipe_closer(int *pipes, int close_mask)
{
for (i = 0; i < 8; i++)
{
if ((mask & (1 << i)) != 0)
close(pipes[i]);
}
}然后可以调用它来关闭不需要的管道:
pipe_closer(pipes, 0xFF); // Close them all - main()
pipe_closer(pipes, 0xFC); // All except 0, 1
pipe_closer(pipes, 0xF3); // All except 2, 3
pipe_closer(pipes, 0xCF); // All except 4, 5
pipe_closer(pipes, 0x3F); // All except 6, 7您只需安排向每个run_cmdN()函数传递正确的掩码,并进行正确的调用。如果pipes数组不是全局的,那么也需要传递。我还将研究如何对数据进行整齐的编码,以便对run_cmdN()的调用尽可能规则和对称。
Kernighan &Plauger的"The Elements of Programming Style“(第二版,1978年;我怀疑很难找到)包含了许多华丽的语录。直接贴切的是(加粗强调,原文为斜体):
子例程调用允许我们在参数列表中汇总代码irregularities ,其中我们可以快速了解发生了什么。子例程本身汇总了代码的,因此不需要使用重复的模式。
这可以看作是编程的DRY (不要重复自己)原则的一部分。err_exit()函数调用封装了三到四行代码-一个打印和一个出口加上大括号,具体取决于您的首选布局。run_command()函数是DRY的一个典型例子。提议的pipe_closer()是另一个。
https://stackoverflow.com/questions/5931309
复制相似问题