簡體   English   中英

Linux命名為fifo non-blocking read select返回假read_fds

[英]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()它也將立即返回與POLLHUPrevents


如OP所述,正確的解決方法是重新打開FIFO。

由於Linux內核僅維護一個內部管道對象來表示每個打開的FIFO(請參閱man 7 fifoman 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM