处理管道,叉子时纾困的策略

时间:2011-11-29 13:42:30

标签: c error-handling fork

我使用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)。但是,这样一个纾困函数所需的所有变量都必须是全局的,因为一些管道被传递给不同的子进程/函数。

2 个答案:

答案 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