2014-02-25 21 views
4

打開一個命名管道(FIFO由mkfifo創建)與非阻塞標誌(開(... O_NONBLOCK)),然後開始輪詢(民意調查(...))。到現在爲止還挺好。 然後在命令行我做了幾個投票()的命名管道與POLLHUP不斷返回,並立即

echo 123 > /tmp/fifo 

管他們都讀出如預期(至少我希望這是他們應該如何正常工作)。

我的問題是,第一回波後,POLLHUP設置,它被卡住,調查從這一點立即返回。

我如何明確 /擺脫POLLHUP

它開始我發瘋:(

是管道的另一端得到關閉(後,這是先前打開的),所以就成了半封閉,但我最終仍然是開放的,充滿活力,我喜歡這種方式。這不是死了,我還可以通過管道接收新的回聲,它只是民調呼聲POLLHUP的河流(我沒有在事件首位甚至要求,但民意調查可以只標記他們無論如何[人民調查:「revents可以包括任何事件中指定的那些,或其中一個值POLLERR,POLLHUP」]),並且因此非常無用。因爲我仍然希望得到關於它的新數據的通知。

我不想關閉它,因爲它不是一次性使用管道,我喜歡重複使用相同的東西而不是將它們扔掉......除此之外,我沒有管道名稱了,只有我有文件描述符(從fd獲取文件名看起來像一個婊子...我也谷歌搜索...)

我仍然相信Linux的力量,並且必須有更好的(更高的性能/比賽條件安全)的方式來做到這一點。

這是我看過,但沒有幫助解決問題。

在我絕望我試圖做這樣的事情,甚至(這並沒有幫助):

int newfd = dup(fds[i].fd); 
    close(fds[i].fd); 
    dup2(newfd, fds[i].fd); 
    close(newfd); 

任何想法?我在做一些完全錯誤的事情嗎? (我現在總是可以回去試圖週期性地讀取所有管道(這實際上是工作的),現在這不是延遲關鍵,但是我不知道如果它是什麼,我會怎麼做......)

這裏有一些代碼重現我的問題(這不是我想要建立的生產代碼,有明顯超過1管,我想輪詢...)

#include <stdio.h> 

#include <sys/types.h> // mkfifo 
#include <sys/stat.h> // mkfifo 

#include <unistd.h> 
#include <fcntl.h> 

#include <errno.h> 
#include <string.h> 

#include <poll.h> 


int main(int argc, char **argv) { 
    char* pipename = "/tmp/fifo"; 
    mkfifo(pipename, S_IWUSR | S_IRUSR | S_IRGRP); 
    int fd = open(pipename, O_RDONLY | O_NONBLOCK); /// O_ASYNC, O_SYNC 

    struct pollfd fds[1]; 
     fds[0].fd = fd; 
     fds[0].events = POLLIN; 
     fds[0].revents = 0; 

    while (1) { 
     int res = poll(fds, 1, 1000); 
     if (res<0) { perror("poll"); return 1; } 
     if (res==0) { printf(".\n"); continue; } 
     printf("Poll [%d]: 0x%04x on %d\n", 0, fds[0].revents, fds[0].fd); 

     char buff[512]; 
     int count = (int)read(fds[0].fd, buff, (size_t)(sizeof(buff)-1)); 
     if (count>=0) { 
      buff[count] = 0; 
      printf("Pipe read %d bytes: '%s'\n", count, buff); 
      usleep(1000*100); /// cpu protector sleep for POLLHUP :) 
     } 
    } 
    return 0; 
} 

注意事項:

我在Linux(lubuntu)平臺(x64)上使用gcc(4.6.3)。但最終我想交叉編譯它以實現嵌入式目標。

我敢肯定,我一定是錯過了一些信息撕成小塊出來,所以問了......

解決方案/解決方法:通過mark4o建議

  1. 解決方法1是打開的管道與O_RDWR而不是O_RDONLY。這樣你不會得到恆定的POLLHUP -s(當然你不會得到任何女巫可能是一個問題)。此外,讀者需要對管道進行寫入許可(在某些情況下可能沒有)。

回答

6

由於管道只提供一個單向通道(對於每個客戶端而不是單獨的雙向通道,就像套接字一樣),所以通常在只有一個進程只需要將數據發送到另一個進程時使用。當作者關閉管道時,POLLHUP(掛機)告訴讀者管道已關閉,它可以完成處理並終止。

可以使用具有多個編寫器的管道,但是如果消息可能大於PIPE_BUF或512字節,則需要小心。否則,因爲它只是一個通道,所以同時寫入的多個寫入器的消息可能會被交織。另外,因爲它是一個單獨的通道,所以您將無法判斷長消息是來自一個客戶端的單個寫入還是來自多個客戶端的多個寫入,除非每個客戶端消息具有一行約定(由換行符終止) 。

POLLHUP表示最後一個寫入程序已關閉管道,並一直持續到另一個進程打開管道進行寫入或被所有讀取程序關閉。如果您不想要這樣,請使用O_RDWR而不是O_RDONLY打開管道,以便管道保持打開狀態。這是有效的,因爲只要你打開它,總會有一個作家(你的程序)。

+0

感謝您提供額外的質量信息。我知道管道原子操作緩衝區的限制,這不是一個問題,我也沒有打算使用1個管道與多個作家,但很多單獨的管道。用O_RDWR打開輸入管道的工作,所以我接受這個答案:)謝謝你的想法。 –