2017-10-15 90 views
0

我正在做一個任務,我必須創建一個鏈接列表,其中包含通過名爲節點的管道進行通信的進程。該程序必須以根進程和稱爲節點1的子進程開始。用戶有四個選項,我卡在選項編號1,用戶應該能夠添加節點(進程)。在讀取管子的過程中掛第二次讀取

根進程應該是唯一要求用戶輸入的進程。其餘的應該循環,直到它碰到讀取塊並等待被寫入。

當用戶輸入1時,程序檢查當前進程是否是最後一個節點(在本例中爲節點1)。如果不是,則該過程通過在每個分支之前創建的管道將輸入寫入下一個節點。如果是,則該過程重置isLast變量並創建一個新管道和叉。子進程(節點2)然後循環並在讀取時卡住,並且父進程跟隨在其後面。然後根再次要求使用輸入。

的問題是,該計劃似乎已經沒有辦法堅持去一次,創建節點2,但第二次通過,節點1掛即使根寫入它在「添加節點」

任何幫助非常感謝!

#include <stdio.h> 
#include <unistd.h> 

int main(){ 
    int isLast = 0; 
    int originPID = getpid(); 
    int input = 0; 
    int node; 
    int p[2]; 

    //Node 1 
    printf("%s\n", "Forking"); 
    pipe(p); 
    int pid = fork(); 

    //Set Node 1 to last 
    if(pid == 0){ 
     isLast = 1; 
     node = 1; 
    } 

    while(input != 4){ 
     //Node Read Block 
     if(getpid() != originPID){ 
      printf("stuck\n"); 
      read(p[0], &input, sizeof(input)); 
      printf("free\n"); 
     } 

     //MENU (Root Only) 
     if(getpid() == originPID){  
      sleep(1); 
      printf("%s", "User Options: Enter a number \n1. Add Node\n2. List Processes\n3. Remove Node\n4. Quit\n"); 
      scanf("%d", &input); 
     } 

     //(1) Add Node 
     if(input == 1){ 
      //Checks if last. 
      if(isLast == 1){ 
       isLast = 0;  //Reset isLast 

       //Create pipe and new process 
       printf("%s\n", "Forking"); 
       pipe(p); 
       pid = fork(); 
       if(pid == 0){  
        isLast = 1; 
        node++;  //Label Node 
       } 
      } 
      //Write to next node 
      else{  
       write(p[1], &input, sizeof(input));  
      } 
     } 
    } 
} 
+1

通過輸入例如'a ',它可以被卡在一個永恆的循環中; 'scanf(「%d」,&input);'then * never * matches。您必須檢查'scanf'的返回值,如果沒有參數被轉換,則放棄直到行尾。 –

+0

另外,什麼是行** 61 **,它不符合您的問題中的代碼。在你的問題61是一個評論。也請閱讀[mcve]並將其製作成一個展示相同問題的最小程序。 –

+0

@AnttiHaapala對於第一個答案,你是在談論一個事實,即如果用戶在提示時輸入'a',程序將進入永久循環?到目前爲止,我還沒有涉及到該部分,因爲我們的教授希望我們現在就能夠承擔適當的投入。但是,這也會影響讀取塊嗎? – DazedFury

回答

1

當最後一個節點從管道讀取1,它必須創建由與新節點它即將建立通信的新的管道。我想這就是爲什麼它叫pipe(p)。但是這是一個問題,因爲p[0]包含文件句柄的唯一副本,它從中讀取自己的輸入。當下一次嘗試讀取輸入時,它將嘗試從它爲下一個節點設置的管道讀取 - 它已經有效地將其與前一個節點斷開連接。

pipe()寫入其文件句柄的數組沒有什麼魔力。手柄只是整數。然後,一個簡單的解決方案就是讓孩子製作並使用從其父代繼承的讀取文件描述符的副本,而不是引用存儲在數組元素中的值。

另外,你應該確定在fork,parent和child每個關閉他們自己不會使用的管道末端副本後。 (Parent關閉讀取結束; child關閉寫入結束。)您可能無法使程序正常工作,但至少會泄漏文件描述符。在某些情況下,打開文件描述符的額外副本可能會導致程序掛起。

+0

感謝您花時間寫出答案。我很抱歉,但是你能否詳細說明讓孩子製作一份文件描述符的意思,我不太明白。此外,我們的教授告訴我們不要在此作業中關閉任何管道,因爲封閉的文件描述符將被回收,這顯然是我們不想要的。 – DazedFury

+0

@DazedFury,文件描述符是存儲在數組元素中的值,而不是數組元素本身。您可以在其他地方存儲相同的值(即不同的變量),然後從那裏使用它。至於關閉,如果你的教授告訴你不要關閉任何文件描述符,那麼當然你應該照他們所說的去做。他們是正確的,文件描述符號碼可以重新使用。不過,我想不出爲什麼會出現問題。 –

+0

這樣做!非常棒的工作,感謝您的幫助。 – DazedFury

相關問題