linux文件設備與I/O:read/write函數 與 阻塞 Block

一,read 函數從打開的設備或文件中讀取數據

#include <unistd.h>
       ssize_t read(int fd, void *buf, size_t count);
       返回值:成功返回讀取的字節數,出錯返回-1並設置errno,若是在調read以前已到達文件末尾,則此次
read返回0


      讀上來的數據保存在緩衝區buf 中,同時文件的當前讀寫位置向後移。注意這個讀寫位置和使用C標準I/O庫時的讀寫位置有可能不一樣,這個讀寫位置是記在內核中的,而使用C標準I/O庫時的讀寫位置是用戶空間I/O緩衝區中的位置。

二,write 函數向打開的設備或文件中寫數據

    #include <unistd.h>
       ssize_t write(int fd, const void *buf, size_t count);
       返回值:成功返回寫入的字節數,出錯返回-1並設置errno


三,阻塞(Block)
       當進程調用一個阻塞的系統函數時,該進程被置於睡眠(Sleep)狀態,這時內核調度其它進程運行,直到該進程等待的事件發生了(好比網絡上接收到數據包,或者調用sleep 指定的睡眠時間到了)它纔有可能繼續運行。
       睡眠狀態相對的是運行(Running)狀態,在Linux內核中,處於運行狀態的進程分爲兩種狀況:正在被調度執行和就緒狀態。

   假設同時監視多個設備,若是read(設備1)是阻塞的,那麼只要設備1沒有數據到達就會一直阻塞在設備1的read 調用上,即便設備2有數據到達也不能處理,使用非阻塞I/O就能夠避免設備2得不到及時處理。
   在open 一個設備時指定了O_NONBLOCK 標誌,read / write 就不會阻塞。以read 爲例,若是設備暫時沒有數據可讀就返回-1,同時置errno 爲EWOULDBLOCK(或者EAGAIN,這兩個宏定義的值相同),表示原本應該阻塞在這裏(would block,虛擬語氣),事實上並無阻塞而是直接返回錯誤,調用者應該試着再讀一次(again)。這種行爲方式稱爲輪詢(Poll),調用者只是查詢一下,而不是阻塞在這裏死等,這樣能夠同時監視多個設備。

      非阻塞I/O有一個缺點,若是全部設備都一直沒有數據到達,調用者須要反覆查詢作無用功,若是阻塞在那裏,操做系統能夠調度別的進程執行,就不會作無用功了。
          select(2) 函數能夠阻塞地同時監視多個設備,還能夠設定阻塞等待的超時時間,從而圓滿地解決了這個問題。

四,阻塞與非阻塞讀終端實例

非阻塞讀終端

   程序開始執行時在0、一、2文件描述符上自動打開的文件就是終端,可是沒有O_NONBLOCK 標誌。因此,讀標準輸入是阻塞的。咱們能夠從新打開一遍設備文件/dev/tty (表示當前終端),在打開時指O_NONBLOCK 標誌。


#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#define MSG_TRY "try again\n"
int main(void)
{
        char buf[10];
        int fd, n;
        fd = open("/dev/tty", O_RDONLY|O_NONBLOCK);
        if(fd<0) {
                perror("open /dev/tty");
                exit(1);
        }
tryagain:
        n = read(fd, buf, 10);
        if (n < 0) {
                if (errno == EAGAIN) {
                        sleep(1);
                        write(STDOUT_FILENO, MSG_TRY,
strlen(MSG_TRY));
                        goto tryagain;
                }
                perror("read /dev/tty");
                exit(1);
        }
        write(STDOUT_FILENO, buf, n);
        close(fd);
        return 0;
}


阻塞讀終端

#include <unistd.h> #include <stdlib.h> int main(void) {         char buf[10];         int n;         n = read(STDIN_FILENO, buf, 10);         if (n < 0) {                 perror("read STDIN_FILENO");                 exit(1);         }         write(STDOUT_FILENO, buf, n);         return 0;}
相關文章
相關標籤/搜索