2011-10-16 55 views
1

我有一個程序,我正在處理,我使用select從管道中選擇要讀取。C使用選擇和從管道讀取

的問題是,我使用if(FD_ISSET(pfd[i][0], &read_set))因爲FD_ISSET是返回0,它沒有通過檢驗,但如果我嘗試使用read(pfd[i][0],&c,sizeof(c))讀它會正常工作,並從管PFD內容[0]從PFD [不同1]就像我想要的。

我想知道這到底是怎麼回事,因爲FD_ISSET返回0,但實際上,我可以讀的內容從它

編輯

全局變量內核將控制我是多麼的進程創建 的下一個代碼將創建管道並使用FD_SET設置位

for(i=0; i<CORES; i++) 
{ 
    if(pipe(pfd[i])==-1) 
     perror("Ocorreu um erro a criar um pipe"); 

    FD_SET(pfd[i][0], &read_set); 
} 

read_set在main()啓動後立即定義。我用()上面的代碼之後,立刻使用fork創建X進程()(X = CORES)

然後這部分在父進程中運行:

while (x<CORES){ 
    int selec = select(pfd[CORES-1][0]+1, &read_set, NULL, NULL, NULL); 

    if(selec>0) 
    { 
     if(FD_ISSET(pfd[x][0], &read_set)) 
     { 
      close(pfd[x][1]); 

      if(read(pfd[x][0],&c,sizeof(c))==-1) 
       perror("Ocorreu um erro a ler do pipe"); 

      printf("c= %f \n",c); 
      c_final+=c; 
      x++; 
     } 
     else 
      printf("\nFile descriptor pfd[%d][0] is not set\n",x); 

    } 
    else if(selec == -1) 
     perror("Ocorreu um erro no select"); 
} 

與此問題是FD_ISSET(pfd[x][0], &read_set)將沒有通過,因爲它不用於PFD [0]設置,但它可以是PFD [1]或反之亦然(因爲我不知道它是否將失敗0或1)

EDIT2:

select()返回一個int read_set中的文件描述符數量。我將CORES設置爲2,因此它創建2個進程和2個管道,並在read_set中設置2個位。我的select()返回int 1.它是否應該返回int 2或0計數(所以它會是0和1 = 2)?

+1

你做錯了什麼事,顯示代碼。 – nos

+0

在調用'select'之前,'fd_set'必須包含所有需要等待的文件描述符,然後在'select'返回後,只有那些準備好的文件將被設置。我猜你以某種方式搞砸了。 –

+1

你是否在使用非阻塞式讀取來做這件事?如果沒有,那麼閱讀將等待輸入,這將使它看起來像你在選擇時有輸入,即使你沒有輸入。 –

回答

5

select第一個參數應該是1+max_fd。儘管pfd[CORES-1][0]可能是最大的,但不能保證。當您填充read_set時,可以計算最大的文件描述符,並將其用於select調用。

另外,在每次調用select之前,您需要重新填充read_set。因此,while循環之外的for循環需要進來。實際上,最好將外部選擇移到外部,並將for循環設置爲read_set,並在另一個循環中的while循環之後結束,以便在每選擇一次返回,您都會處理所有已發信號的描述符,而無需再次進入選擇狀態


編輯:澄清我的意思是關於循環:你應該檢查所有描述符每次選擇返回。但是你不能僅僅調用一次select,因爲不能保證所有的答案都會一次就緒。所以你做這樣的事情:

for (i=0; i != CORES; ++i) 
{ 
    // Call pipe() and populate pfd[i] 
} 

while (!finished) // Need a proper condition to terminate this loop 
{ 
    // Setup read_set 
    FD_ZERO(&read_set); 
    for (i=0; i != CORES; ++i) 
    { 
     FD_SET(pfd[i][0], &read_set); 
     // find max_fd here 
    } 
    // select here 
    if (select(max_fd+1, blahblah) > 0) 
    { 
     for (i=0; i != CORES; ++i) // This used to be while(x < CORES). But a for loop would do 
     { 
      // Check the fd, and process 
     } 
    } 
    else 
    { 
     // error in select 
    } 
} 
+0

重新填充read_set是什麼意思?我在關於循環和while的解釋中有點困惑。你可以給我一個例子嗎?謝謝你的回答 – andrepcg

+0

@andrepcg我的意思是for循環從0到CORES,爲'read_set'變量調用'FD_SET()'。當然,不用調用'pipe'。每當你打算調用'select'(這是來自內存,所以你可能想檢查一下),你應該重複這個循環。我將編輯我的答案以澄清其餘部分。 – vhallac

+0

但是如果我在選擇之前已經爲每個文件描述符都做了FD_SET,爲什麼我會再次這樣做?謝謝! – andrepcg

1

我建議在這種情況下,你試圖讀取所有這些不同的文件描述符,並檢查非阻塞寫入(也就是說,你似乎試圖檢查是否有任何一個管道是活動的),你去poll()而不是select()除非由於某些原因,你必須使用select()。通過民意調查,您可以簡單地將所有文件描述符設置爲struct pollfd的陣列,併爲他們提供您想要測試的事件。然後返回poll()的結果會讓你知道有多少文件描述符有事件。我認爲這種方法對您來說可以更輕鬆地進行管理。舉例來說,你可以做類似如下:

struct pollfds descriptors[CORES * 2] = {0}; 

for(int i=0; i<CORES; i++) 
{ 
    if(pipe(pfd[i])==-1) 
     perror("Ocorreu um erro a criar um pipe"); 

    //wait for either a read on pipe[0] or a non-blocking write on pipe[1] 
    descriptors[i*2].fd = pfd[i][0]; 
    descriptors[i*2].events = POLLIN; 
    descriptors[(i*2)+1].fd = pdf[i][1]; 
    descriptors[(i*2)+2].events = POLLOUT; 
} 

while (x < CORES) 
{ 
    int num_events = poll(descriptors, CORES * 2, -1); //infinite timeout period 

    //...check your descriptors array for events 
} 
+0

這是我正在處理的任務,我需要使用select()從特定管道讀取 – andrepcg