2009-05-23 39 views
4

我正在寫一個C程序。下面介紹一下它的作用:從C:中讀取FIFO:select()不返回?

  • 創建N使用mkfifo
  • 打開它們讀取(與O_NONBLOCK標誌)
  • 打開他們寫
  • 產生一個線程

在FIFO的線程運行在一個循環中:

  • 創建一個fd_set描述文件對於所有n FIFO的職權範圍
  • 通話選擇(N,& my_set,NULL,NULL,NULL)
  • 對於每一個的fd準備好進行I/O(FD_ISSET(FD,& my_set)):
    • 閱讀從FD字符串(讀(FD,BUF,buf_len))
    • 打印字符串
    • 如果字符串== 「殺」,標誌着FD已經死了,從列表中刪除(N--)
    • 如果n == 0,則終止線程

在主程序:

  • 對於i = 0至n
    • 寫入FDS [I]與一個字符串(寫(FDS [I],buf中,buf_len) )
  • 對於i = 0至n
    • 寫入FDS [I]與字符串 「殺」
  • 加入的線程上,我創建
  • 退出

我所看到的行爲是選擇()將與長度1回一次,是在列表中的第一個FD。通過循環第二次,選擇將永遠坐在那裏。

這裏是我的輸出:

thread created 
Waiting on 4 file descriptors 
> Wrote 'Hello to target 0 from writer 0' to 0 
> Wrote 'Hello to target 0 from writer 1' to 1 
> Wrote 'Hello to target 1 from writer 0' to 2 
> Wrote 'Hello to target 1 from writer 1' to 3 
> Sending kill to 0:0 (#0) 
> Sending kill to 0:1 (#1) 
> Sending kill to 1:0 (#2) 
> Sending kill to 1:1 (#3) 
< Got string: 'Hello to target 0 from writer 0' 
Waiting on 4 file descriptors 
^C 

操作系統是Linux,如果它很重要。

鏈接代碼:https://dl.getdropbox.com/u/188590/fifotest.c (對不起這有點令人髮指)

感謝, 彌敦道

+0

我認爲我們將需要查看代碼,不管是否已經過消毒。日誌信息並不完全清楚 - 我確定編寫器0和1是關於什麼的,如果'0'意思是'將文件描述符0'作爲標準輸入,這似乎令人驚訝。您是否仔細檢查每次系統調用的錯誤? – 2009-05-23 02:32:53

+0

好吧,我把一個鏈接到問題中的代碼。這是在https://dl.getdropbox.com/u/188590/fifotest.c 我相信我一絲不苟地檢查錯誤。數字(如0)不是fd數字,它們是數組中的索引。 – Nathan 2009-05-23 02:59:02

+0

拿到代碼:得了輸出結尾: <得到的字符串:「你好,從作家針對0 0」 4個文件描述符等待 <得到的字符串:「殺0:0」 等待3個文件描述符 ..這比你現在看得更遠了。 – 2009-05-23 03:07:18

回答

4

正如蘭斯·理查森說,第一個問題是,你需要傳遞的最大文件描述符的數量加一,而不是文件描述符的數量。

然後你必須清理在偵聽線程管家 - 我大部分的數據,但最終聽6個文件描述符,而不是4報告的數量是目前規模最大的FD,不文件描述符的個數

你也有一個問題,你寫一個字符串加一個空字節到每個管道,然後是第二個字符串加一個空字節。由於調度是非確定性的,因此主程序實際上會將其字符串寫入每個fifo,因此當偵聽器線程讀取它時,它會讀取這兩個字符串。當我打印出長度時,總長度爲41(read_len),但每strlen()的字符串長度爲31.換句話說,第一次讀取包括'殺死'部分,但您沒有注意到由於第一條消息結尾處的結尾爲空,打印輸出。因此,你在等待那永不會發生的事情。

2

在呼叫中的第一個參數來選擇()應該是最高編號的文件描述符加1 ,而不是fd_set中的文件描述符的數量。

這裏是我改變來解決這個問題:

--- fifotest-1.c  2009-05-22 23:44:03.000000000 -0400 
+++ fifotest.c 2009-05-22 23:34:00.000000000 -0400 
@@ -34,19 +34,22 @@ 
    sim_arg_t* ifs = arg; 
    uint32_t num_ifs; 
    uint32_t select_len; 
+ int maxfd; 

     num_ifs = ifs->num_ifs; 
    while (num_ifs > 0) { 
       FD_ZERO (&set); 
       select_len = 0; 
-    for (i = 0; i < ifs->num_ifs; ++i) { 
+    for (maxfd=0, i = 0; i < ifs->num_ifs; ++i) { 
         if (ifs->if_list[i].valid) { 
           FD_SET(ifs->if_list[i].fh, &set); 
-        ++select_len; 
+        if (ifs->if_list[i].fh > maxfd) 
+         maxfd = ifs->if_list[i].fh; 
+        select_len++; 
         } 
       } 
       printf("Waiting on %d file descriptors\n", select_len); 
-    ret = select(select_len, &set, NULL, NULL, NULL); 
+    ret = select(maxfd+1, &set, NULL, NULL, NULL); 
       if (ret < 0) { 
         fprintf(stderr, "Select returned error!\n"); 
         continue;