2011-11-29 19 views
1

我用fork写了一个小程序来创建使用pipes进行通信的新进程。应用防御性编程,我检查每个返回值。如果返回值指示出错了,我想释放所有资源,关闭所有管道和父进程以等待它的子进程终止。现在,如果发生错误,最好的方法是什么?解决管道,叉子问题时的策略

目前,我做这样说:

/* 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

'goto'是你的朋友。 –

+0

@mort:你不检查close()系统调用的任何返回值。你也不期望'exit()'不能退出:-) – 2011-11-29 13:50:23

+0

@Vlad:'exit()'没有返回值。 – mort

回答

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); 
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