我使用fork
编写了一个小程序来创建使用pipe
进行通信的新进程。应用防御性编程,我检查每个返回值。如果返回值表明出现了问题,我想释放所有资源,关闭所有管道和父进程,等待它的子进程终止。现在,如果发生错误,最好的纾困方法是什么?
目前,我这样做:
/* initialize pipes */
if(pipe(p1fd) == -1) {
(void) printError("Could not init pipe 1");
exit(EXIT_FAILURE);
}
if(pipe(p2fd) == -1) {
(void) printError("Could not init pipe 2");
(void) close(p1fd[0]);
(void) close(p1fd[1]);
exit(EXIT_FAILURE);
}
switch (pid = fork()) {
case -1:
(void) printError("Could not fork");
(void) close(p1fd[0]);
(void) close(p1fd[1]);
(void) close(p2fd[0]);
(void) close(p2fd[1]);
exit(EXIT_FAILURE);
break;
case 0: /* child process */
break;
default: /* parent process */
break;
}
如果需要更多资源,这会非常麻烦。我想到的另一种方法是提供一个救援功能,如果管道实际上已经打开,那么只需关闭所有管道而不关心(同样是为了释放内存并在子进程上调用wait
)。但是,这样一个纾困函数所需的所有变量都必须是全局的,因为一些管道被传递给不同的子进程/函数。
答案 0 :(得分:4)
您可以使用goto
来避免在每个失败分支中重复相同的代码:
if (pipe(p1fd) == -1) {
printError("Could not init pipe 1");
goto pipe1_fail;
}
if (pipe(p2fd) == -1) {
printError("Could not init pipe 2");
goto pipe2_fail;
}
switch (pid = fork()) {
case -1:
printError("Could not fork");
goto fork_fail;
case 0: /* child process */
...
exit(...);
default: /* parent process */
...
exit(...);
}
fork_fail:
close(p2fd[0]);
close(p2fd[1]);
pipe2_fail:
close(p1fd[0]);
close(p1fd[1]);
pipe1_fail:
exit(EXIT_FAILURE);
答案 1 :(得分:2)
虽然某些人不赞成goto
,但通常是used for error handling,e。 G。 in the Linux kernel。但是要小心保持代码结构良好,并且不要夸大使用它。
此处示例:
/* initialize pipes */
if(pipe(p1fd) == -1) {
(void) printError("Could not init pipe 1");
goto error;
}
if(pipe(p2fd) == -1) {
(void) printError("Could not init pipe 2");
goto closep1fd;
}
switch (pid = fork()) {
case -1:
(void) printError("Could not fork");
goto closep2p1fd;
case 0: /* child process */
break;
default: /* parent process */
break;
}
closep2p1fd:
close(p2fd[0]);
close(p2fd[1]);
closep1fd:
close(p1fd[0]);
close(p1fd[1]);
error:
exit(EXIT_FAILURE);
return -1; // maybe better if it is a deeply nested function