2011-11-29 61 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