[英]Linux named fifo non-blocking read select returns bogus read_fds
類似於不久前在內核3.x上問的問題 ,但我在4.9.37上看到了。 使用mkfifo -m 0666
創建命名的fifo。 在讀取方面,它用
int fd = open(FIFO_NAME, O_RDONLY | O_NONBLOCK);
結果fd
傳遞給對select()
的調用。 一切正常,直到我運行echo >> <fifo-name>
。
現在,在select()
返回之后, fd
出現在read_fds
。 fd
上的read()
將返回一個字節的數據。 到現在為止還挺好。
下次調用select()
並返回時, fd
仍出現在read_fds
,但read()
將始終返回零,意味着沒有數據。 實際上,讀取端將消耗100%的處理器容量。 這與所引用問題所觀察到的問題完全相同。
有人看到過同樣的問題嗎? 以及如何解決或正確解決呢?
我已經弄清楚了,如果我關閉了fifo的讀取端,然后再次將其重新打開,它將可以正常工作。 可能沒問題,因為我們沒有發送大量數據。 雖然這不是一個不錯的方法或一般的解決方法。
這是預期的行為,因為輸入結束的情況導致read()
不會阻塞; 它立即返回0。
如果您看一下man 2 select ,它將清楚地表明,如果該描述符上的read()
不會阻塞(在select()
調用時),則會在readfds
中設置一個描述符。
如果您使用poll()
它也將立即返回與POLLHUP
在revents
。
如OP所述,正確的解決方法是重新打開FIFO。
由於Linux內核僅維護一個內部管道對象來表示每個打開的FIFO(請參閱man 7 fifo和man 7管道 ),因此Linux中的健壯方法是在遇到輸入結束時向FIFO打開另一個描述符( read()
返回0),然后關閉原始文件。 在兩個描述符都打開的時間內,它們引用相同的內核管道對象,因此不會出現爭用窗口或數據丟失的風險。
在偽C中:
fifoflags = O_RDONLY | O_NONBLOCK;
fifofd = open(fifoname, fifoflags);
if (fifofd == -1) {
/* Error checking */
}
/* ... */
/* select() readfds contains fifofd, or
poll() returns POLLIN for fifofd: */
n = read(fifofd, buffer, sizeof buffer)
if (!n) {
int tempfd;
tempfd = open(fifopath, fifoflags);
if (tempfd == -1) {
const int cause = errno;
close(fifofd);
/* Error handling */
}
close(fifofd);
fifofd = tempfd;
/* A writer has closed the FIFO. */
} else
/* Handling for the other read() result cases */
Linux中的文件描述符分配策略是tempfd
將是編號最小的空閑描述符。
在我的系統(Core i5-7200U筆記本電腦)上,以這種方式重新打開FIFO不到1.5 µs。 也就是說,每秒可以完成約680,000次。 我認為,即使在低功率的嵌入式Linux計算機上,這種重新開放也不是任何明智情況的瓶頸。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.