簡體   English   中英

管道上的非阻塞讀取

[英]Non-blocking read on pipe

可以在管道上進行非阻塞 I/O 嗎? fcntl 未能設置 O_NONBLOCK。 Linux 編程接口的第 918 頁包含一個表“從管道或 FIFO (p) 讀取 n 字節的語義”。 下表列出了管道和 FIFO 的行為,其中一列標題為啟用了 O_NONBLOCK? 這意味着您可以在管道上設置 O_NONBLOCK 標志。 這個對嗎? 以下代碼未能設置標志,但 fcntl(2) 不報告錯誤。

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

int main()
{
    int fds[2];
    pid_t pid;
    char wr_buf[100];
    char rd_buf[100];

    pipe(fds);

    pid = fork();

    if ( pid )
    {
        while (1 )
        {
            memcpy( wr_buf, "abcdefghi\0",10);
            write( fds[1], wr_buf, 10);
            sleep(2);
        }
    }
    else
    {
        int retval = fcntl( fds[0], F_SETFL, fcntl(fds[0], F_GETFL) | O_NONBLOCK);
        printf("Ret from fcntl: %d\n", retval);
        while (1)
        {
            ssize_t r=read( fds[0], rd_buf, 10 );
            printf("read: %d\n", r);

            if ( r > 0 )
            {
                printf("Buffer: %s\n", rd_buf);
            }
            else
            {
                printf("Read nothing\n");
                perror("Error was");
                sleep(1);
            }
        }
    }
}

pipe 和 O_NONBLOCK 沒有什么特別之處。 以下示例按預期工作。 我沒有檢查每次調用的每個 retval 以使示例更具可讀性。 現實世界的應用程序必須進行檢查。

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

int main()
{
    int fds[2];
    pid_t pid;
    char buf[100];

    pipe(fds);

    pid = fork();

    if ( pid )
    {
        while (1 )
        {
            memcpy( buf, "abcdefghi\0",10);
            write( fds[1], buf, 10);
            sleep(2);
        }
    }
    else
    {
        int retval = fcntl( fds[0], F_SETFL, fcntl(fds[0], F_GETFL) | O_NONBLOCK);
        printf("Ret from fcntl: %d\n", retval);
        while (1)
        {
            ssize_t r=read( fds[0], buf, 10 );
            printf("read: %d\n", r);

            if ( r > 0 )
            {
                printf("Buffer: %s\n", buf);
            }
            else
            {
                printf("Read nothing\n");
                perror("Error was");
                sleep(1);
            }
        }
    }
}

寫完我的例子后,我檢查了你的代碼,發現:

flags = fcntl(pfd[0], F_GETFD);
flags |= O_NONBLOCK;
if (fcntl(pfd[0], F_SETFD, flags))

請將F_SETFD更改為F_SETFL以及獲取操作。 您不會更改file descriptor flags ,而是更改file status flags :-)

來自man 3 fcntl

文件描述符標志以下命令操作與文件描述符關聯的標志。 目前,只定義了一個這樣的標志:FD_CLOEXEC,close-on-exec 標志。 如果 FD_CLOEXEC 位為 0,則文件描述符將在 execve(2) 中保持打開狀態,否則將關閉。

文件狀態標志每個打開的文件描述都有某些相關的狀態標志,由 open(2) 初始化,並可能由 fcntl() 修改。 重復的文件描述符(使用 dup(2)、fcntl(F_DUPFD)、fork(2) 等)引用相同的打開文件描述,因此共享相同的文件狀態標志。

F_SETFL (int) 將文件狀態標志設置為 arg 指定的值。 arg 中的文件訪問模式(O_RDONLY、O_WRONLY、O_RDWR)和文件創建標志(即 O_CREAT、O_EXCL、O_NOCTTY、O_TRUNC)被忽略。 在 Linux 上,此命令只能更改 O_APPEND、O_ASYNC、O_DIRECT、O_NOATIME 和O_NONBLOCK標志。 無法更改 O_DSYNC 和 O_SYNC 標志; 請參閱下面的錯誤。

暫無
暫無

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

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