簡體   English   中英

使用fifo以非阻塞模式打開並選擇

[英]Using fifo open in non-blocking mode with select

我有兩個進程A和B.通信流總是A - > B,但我需要使用命名管道來完成它,因為我必須在B進程內的select調用中使用管道文件描述符,並寫入數據當任何一個或兩個進程退出時,管道必須保持不變。

管道兩端以非阻塞模式打開。 在過程A:

int push_fifo_fd = open(FIFO_NAME, O_WRONLY | O_NONBLOCK | O_CREAT, 0644);

在流程B中:

int fd = open(FIFO_NAME, O_RDONLY | O_NONBLOCK | O_CREAT, 0644);

Q1。 進程B使用curl多接口,因此我得到curl多句柄的fd_sets並將“fd”描述符添加到讀取fd_set,而不是調用select,以獲得可用於讀取和寫入的文件描述符。 在每次調用調用中,“fd”包含在結果讀取fd_set中,但是讀取返回0,即使寫入結束也是如此。 這導致進程B使用100%的處理器時間。 我提到我不知道訂購哪個管子的末端是打開的。 B的相關代碼:

while (1)
{
    fd_set read_fds, write_fds, err_fds;

    FD_ZERO(&read_fds);
    FD_ZERO(&write_fds);
    FD_ZERO(&err_fds);

    FD_SET(fifo_fd, &read_fds);
    // some code
    ccode = curl_multi_fdset(curlm, &read_fds, &write_fds, &err_fds, &max_fd);
    max_fd = MAX(max_fd, fifo_fd);

    rc = select(max_fd + 1, &read_fds, &write_fds, &err_fds, &timeout);
    switch (rc)
    {
        case -1:
            WARN("select");
            continue;

        case 0:
        default:
            {
                if (FD_ISSET(fifo_fd, &read_fds))
                {
                    // read from the fifo_fd
                }

                /* Now look at the handles that need attention */
                int old_running_handles = running_handles;

                ccode = curl_multi_perform(curlm, &running_handles);
                if (ccode != CURLM_OK && ccode != CURLM_CALL_MULTI_PERFORM)
                {
                    WARN("curl_multi_perform error: %s", curl_multi_strerror(ccode));
                    continue;
                }

                if (running_handles != old_running_handles)
                {
                    CURLMsg *curl_msg;
                    int left_msgs = 0;
                    while ((curl_msg = curl_multi_info_read(curlm, &left_msgs)) != NULL)
                    {
                        // treat each easy handle
                    }
                }
            }
            break;
    }
}

Q2。 在“man 7 fifo”中說“進程可以在非阻塞模式下打開FIFO。在這種情況下,即使在寫入端沒有人打開,只讀打開也會成功,只寫打開會失敗使用ENXIO(沒有這樣的設備或地址),除非另一端已經打開。“ 但是進程A總是可以在非阻塞模式下成功打開管道的寫入端,即使讀取端未打開也是如此。 這是為什么? 我測試的平台是Ubuntu服務器12.04.3,內核3.8.0-29。

Q1期望由select()poll() 查看鏈接的問題 優雅的解決方案是在同一個fifo上打開另一個fd並關閉原始fd。

我相信在某些版本的內核中也會出現Q2。 男人7 fifo有一段關於它:

   Under Linux, opening a FIFO for read and write will succeed both in 
   blocking and nonblocking mode.  POSIX leaves this behavior undefined.
   This can be used to open a FIFO for writing while there are no
   readers available.

該段似乎聲稱您可以隨時成功打開fifo的寫入結束,如原作者在Q2中所觀察到的那樣。

雖然它似乎與前一段相矛盾,因為原來的問題也是從男子7 fifo頁面引用的,基本上說開放會失敗而不是成功:

   A process can open a FIFO in nonblocking mode.  In this case, opening
   for read-only succeeds even if no one has opened on the write side
   yet and opening for write-only fails with ENXIO (no such device or
   address) unless the other end has already been opened.

我看到在4.9.37內核上,當讀取端未打開時,以非阻塞模式打開寫端會失敗。 我猜,它必須已從3.8版更改為4.9版。

因為:

在Linux下,打開FIFO進行讀寫將在阻塞和非阻塞模式下成功。 POSIX未定義此行為。 這可用於打開FIFO進行寫入,而沒有可用的讀取器。 使用連接的兩端以便與自身通信的進程應該非常小心以避免死鎖。

來自http://linux.die.net/man/7/fifo

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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