2010-05-22 30 views
13

從我一直在閱讀上由The Open Group網站上fcntlopenreadwrite,我得到的印象是,是否O_NONBLOCK被設置在一個文件描述符,因此無論是非阻塞I/O是用來與描述符應該是該文件描述符的屬性,而不是底層文件。作爲文件描述符裝置的屬性,例如,如果我複製一個文件描述符或打開另一個描述符到相同的文件,然後我可以使用阻塞I/O與一個並且與其它非阻塞I/O。是否將O_NONBLOCK設置爲文件描述符或基礎文件的屬性?

與FIFO進行實驗,但是,看來,它不可能同時具有阻塞I/O描述符和非阻塞I/O描述符的FIFO(因此無論O_NONBLOCK設置是底層的一個屬性文件[先進先出]):

#include <errno.h> 
#include <fcntl.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 

int main(int argc, char **argv) 
{ 
    int fds[2]; 
    if (pipe(fds) == -1) { 
     fprintf(stderr, "`pipe` failed.\n"); 
     return EXIT_FAILURE; 
    } 

    int fd0_dup = dup(fds[0]); 
    if (fd0_dup <= STDERR_FILENO) { 
     fprintf(stderr, "Failed to duplicate the read end\n"); 
     return EXIT_FAILURE; 
    } 

    if (fds[0] == fd0_dup) { 
     fprintf(stderr, "`fds[0]` should not equal `fd0_dup`.\n"); 
     return EXIT_FAILURE; 
    } 

    if ((fcntl(fds[0], F_GETFL) & O_NONBLOCK)) { 
     fprintf(stderr, "`fds[0]` should not have `O_NONBLOCK` set.\n"); 
     return EXIT_FAILURE; 
    } 

    if (fcntl(fd0_dup, F_SETFL, fcntl(fd0_dup, F_GETFL) | O_NONBLOCK) == -1) { 
     fprintf(stderr, "Failed to set `O_NONBLOCK` on `fd0_dup`\n"); 
     return EXIT_FAILURE; 
    } 

    if ((fcntl(fds[0], F_GETFL) & O_NONBLOCK)) { 
     fprintf(stderr, "`fds[0]` should still have `O_NONBLOCK` unset.\n"); 
     return EXIT_FAILURE; // RETURNS HERE 
    } 

    char buf[1]; 
    if (read(fd0_dup, buf, 1) != -1) { 
     fprintf(stderr, "Expected `read` on `fd0_dup` to fail immediately\n"); 
     return EXIT_FAILURE; 
    } 
    else if (errno != EAGAIN) { 
     fprintf(stderr, "Expected `errno` to be `EAGAIN`\n"); 
     return EXIT_FAILURE; 
    } 

    return EXIT_SUCCESS; 
} 

這讓我思考:有沒有可能有一個非阻塞I/O描述符和阻塞I/O描述符相同的文件,如果是這樣,那麼它取決於關於文件的類型(常規文件,FIFO,塊特殊文件,字符特殊文件,套接字等)?

+0

我很想知道這件事,因爲如果O_NONBLOCK被設置爲底層文件的屬性,那麼打開帶有O_NONBLOCK *的文件的一個調用*不在* oflags *中設置*然而可能會返回帶有O_NONBLOCK標誌的文件描述符。 – 2010-05-22 22:06:52

回答

22

O_NONBLOCK是打開的文件的描述的性質,而不是文件描述符的,也不是底層文件的。

是的,你可能有單獨的文件描述符打開同一個文件,其中之一是阻塞,另一個是非阻塞的。

您需要區分FIFO(使用mkfifo()創建)和管道(使用pipe()創建)。

注意的阻斷狀態是「打開文件的描述」的屬性,但在簡單的情況下,有文件描述符和打開文件描述之間的一個一對一的映射。 open()函數調用將創建一個新的打開的文件描述和一個新的文件描述符,用於引用打開的文件描述。

當您使用dup(),你有兩個文件描述符共享一個打開文件的描述,和屬性都屬於開放文件描述。 fcntl()的說明表示F_SETFL影響與文件描述符關聯的打開文件描述。需要注意的是lseek()調整與文件描述符關聯的打開文件描述的文件中的位置 - 所以它影響從原來的1個重複的其他文件描述符。

刪除該錯誤代碼處理,以減少它,你必須:

int fds[2]; 
pipe(fds); 
int fd0_dup = dup(fds[0]); 
fcntl(fd0_dup, F_SETFL, fcntl(fd0_dup, F_GETFL) | O_NONBLOCK); 

現在無論fd0_dup和FDS [0]參見(因爲dup())相同的開放文件描述,所以fcntl()操作影響兩個文件描述符。

if ((fcntl(fds[0], F_GETFL) & O_NONBLOCK)) { ... } 

因此,這裏觀察到的行爲是POSIX所要求的。

+2

哦,好的。所以「文件描述符」和「文件描述」是有區別的。兩個文件描述符可以共享相同的文件描述,並且這些標誌是描述的屬性。再次查看文檔以打開文檔,它表示該函數「將創建一個打開的文件描述」。 我認爲我現在明白了。 – 2010-05-22 22:35:14

+0

是的,你明白了。 – 2011-08-14 19:47:46

+1

@DanielTrebbien:一些標誌屬於文件描述符,例如'FD_CLOEXEC'。 – jfs 2015-02-12 16:57:50