2013-03-06 69 views
0

我正在爲一個父級播放連接N個子進程的作業編寫一個程序。該程序使用管道在進程之間傳遞遊戲移動。用fork()和pipe()調用競爭條件

但是,我遇到了修復存在於我的程序中的競爭條件的問題。在遊戲結束後,子進程會掛起一個read()調用。這隻有在有多個子進程時纔會發生。

我已經嘗試了幾個東西,比如命名的信號燈,但我對叉子,管道和IPC還是很新的東西。我已與相關的代碼要點(我試圖把它清理乾淨是最好的,我可以爲可讀性)位置:

Gist with relevant code

任何幫助,將不勝感激

編輯

以下是添加了聲明的要點的相關來源。

int main (int argc, char const *argv[]) 
{ 
    int dimension = 8, children = 2, i; 
    int child_play_to_win = 0; 
    int fd[children][4]; 
    pid_t childpid[children]; 
    Board** boards = (Board**) malloc(sizeof(Board*) * children); 
    GameMove* lastMove, *tmpMove; 
    char buf[80]; 
    for(i = 0; i < children; i++) { 
    generate_board(&(boards[i]), dimension); 
    int tmp[2]; 
    pipe(tmp); 

    // child read 
    fd[i][0] = dup(tmp[0]); 
    // parent write 
    fd[i][1] = dup(tmp[1]); 

    pipe(tmp); 
    // parent read 
    fd[i][2] = dup(tmp[0]); 
    // child write 
    fd[i][3] = dup(tmp[1]); 

     childpid[i] = fork(); 

    if(childpid[i] == -1) { 
     perror("fork"); 
     exit(1); 
    } 
    if(childpid[i] == 0) { 
     srand(getpid()); 
     close(fd[i][1]); 
     close(fd[i][2]); 
     while(!boards[i]->finished) { 
     // Read in move from parent 
     printf("child[%d] about to read\n", getpid()); 
     read(fd[i][0], &buf, sizeof(GameMove)); 

     // repeat parent move on this board 

     if(gameNotFinished) { 
      // make child move 

      // write move back to parent 

      write(fd[i][3], lastMove, sizeof(GameMove)); 

      // If the board is finished (there was a win), 
      if (!gameNotFinihsed) { 
      // Child wins 
      close(fd[i][0]); 
      close(fd[i][3]); 
      printf("child[%d] ending\n", getpid()); 
      break; 
      } 
     } 
     else { 
      // Parent won 
      close(fd[i][0]); 
      close(fd[i][3]); 
      break; 
     } 
     } 
    dealloc(boards[i]); 
    exit(0); 
    } 
} 

    // When this hits children amount, all games are done 
    int games_complete = 0; 
    // Make first move to all children 
    for (i = 0; i < children; i++) { 
    close(fd[i][0]); 
    close(fd[i][3]); 
    lastMove = placePieceAtBestPosition(boards[i], 1); 
    printf("parent writing to child[%d]\n", childpid[i]); 
    write(fd[i][1], lastMove, sizeof(GameMove)); 
    } 
    while (games_complete != children) { 
    for (i = 0; i < children; i++) { 
     // Read move from child 
     read(fd[i][2], &buf, sizeof(GameMove)); 

     // repeat child move 

     // Check for a child win... 
     if (!checkForWin(boards[i], 2)) { 
     // No win yet, place piece at best position 

     lastMove = placePieceAtBestPosition(boards[i], 1); 

     // check for win again 
     boards[i]->finished = checkForWin(boards[i], 1); 
     // Write move back to child 
     write(fd[i][1], lastMove, sizeof(GameMove)); 

     // If we won, close everything up and increment 
     // the games_complete counter. 
     if(boards[i]->finished) { 
      close(fd[i][1]); 
      close(fd[i][2]); 
      games_complete++; 
     } 
     } else { 
    // write back child move if there was a win 
     write(fd[i][1], lastMove, sizeof(GameMove)); 
     close(fd[i][1]); 
     close(fd[i][2]); 
     printf("Parent lost!):\n"); 
     games_complete++; 
     } 
    } 
    } 
+2

請發表(相關部分)代碼直接在你的問題,而不是通過鏈接。謝謝。 – 2013-03-06 18:17:48

+0

打到我的第一件事就是你在創建管道後不需要這些'dup'調用。特別是因爲你不關閉原始文件描述符。根據您製作的子進程數量的不同,這可能會填滿文件描述符表。 – 2013-03-06 18:19:46

+0

*爲什麼*你會鏈接100多行代碼,並且*不包括源文件頂部的開啓函數聲明? – WhozCraig 2013-03-06 18:19:57

回答

0

我想我知道你的問題是什麼。當你分叉每個孩子時,你關閉它的管道的父側。然而,每個孩子仍然打開所有以前孩子的管道的父方。因此,只有最後創建的子項將其管道的父級關閉。

建議你改變:

close(fd[i][1]); 
close(fd[i][2]); 

喜歡的東西:

for (j = 0; j <=i; j++) { 
    close(fd[j][1]); 
    close(fd[j][2]); 
} 
+0

好的。我仍然對閱讀的孩子產生懷疑,但這絕對是我錯過的。 – 2013-03-06 19:14:49