如何理解io?
IO指的是計算機系統中輸入(input)和輸出(Output)的過程,以計算機本身為參照物,是計算機與外部設備進行數據交互的機制。
輸入(Input)是向計算機發送數據的過程,而輸出(Output)是從計算機向外部設備發送數據的過程。
IO操作主要包括等待和拷貝兩個步驟:
IO = 等待 + 拷貝(等待是主要矛盾)
在等待外部設備準備好數據后,CPU通過針腳發送中斷信號通知操作系統。操作系統進入內核態,進行數據拷貝。
因此,IO操作基本可以概括為等待和拷貝兩個動作。
高效IO
在IO操作中,時間主要消耗在等待上,因為拷貝的時間相對于等待來說要短得多。
高效的IO操作意味著減少等待時間,從而增加拷貝操作在整個過程中的比重。
第一種IO模型:阻塞IO模型
阻塞IO模型的特點是在系統調用時,如果外部設備未準備好數據,進程會一直等待數據準備就緒。一旦數據準備好,數據就會從內核空間拷貝到用戶空間,并返回成功標識符。
ssize_t recv(int sockfd, void *buf, size_t len, int flags); ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
ssize_t send(int sockfd, const void *buf, size_t len, int flags); ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
第二種IO模型:非阻塞IO模型
非阻塞IO模型與阻塞IO模型的最大區別在于,當沒有數據可用時,非阻塞IO會立即返回,并返回EWOULDBLOCK錯誤碼。
#include <iostream> #include <fcntl.h> #include <unistd.h> using namespace std; void SetNoBlock(int fd){ int info=fcntl(fd,F_GETFL); if(info
第三種IO模型:信號驅動IO模型
在信號驅動IO模型中,當內核準備好數據時,會使用SIGIO信號通知應用程序進行IO操作。
與非阻塞IO不同的是,信號驅動IO不會循環檢測數據是否準備好,而是當數據真正可用時發送SIGIO信號,確保IO操作成功。
第四種IO模型:IO多路轉接模型
IO多路轉接模型包括select、poll和epoll等方法。通過允許單個線程同時監控多個文件描述符的I/O狀態,可以避免為每個I/O操作創建單獨線程,從而減少資源消耗和上下文切換開銷。
雖然圖示上看起來與阻塞IO模型類似,但IO多路轉接的關鍵在于可以一次性等待多個文件的狀態變化(一切皆文件)。
第五種IO模型:異步IO模型
前四種模型都是同步IO,因為它們參與了等待或拷貝的過程。阻塞IO參與了等待和拷貝,非阻塞IO至少參與了拷貝,IO多路轉接可以管理多個文件并設置為非阻塞。
異步IO則直接返回,等待和拷貝的過程都由系統完成。處理完成后,系統通過事件、信號等方式通知應用程序。
同步通信和異步通信
同步通信需要參與等待和拷貝的過程,參與其中任何一個步驟即為同步。
異步通信雖然也需要等待和拷貝,但這兩個過程完全由系統完成,調用者無需關心這兩個過程。系統處理完畢后會通知調用者。
需要注意的是,線程同步和線程互斥與此概念不同。它們是為了保護臨界資源,確保資源的一致性。
阻塞和非阻塞
阻塞調用會在調用成功之前掛起線程,直到得到結果后才返回。
非阻塞調用會立即返回,不會阻塞線程。
fcntl函數
文件描述符默認是阻塞的。
函數原型
#include <unistd.h> #include <fcntl.h> int fcntl(int fd, int cmd, ... /* arg */ );
cmd是命令,指定操作類型。主要操作類型包括:
- 獲取、設置文件狀態信息:cmd=F_GETFL,F_SETFL。
- 復制現有描述符:cmd=F_DUPFD。
- 獲取、設置文件描述符標志:cmd=F_GETFD,F_SETFD。
- 獲取、設置異步IO所有權:cmd=F_GETOWN,F_SETOWN。
- 獲取、設置記錄鎖:cmd=F_GETLK,F_SETLK,F_SETLKW。
cmd | 功能 |
---|---|
F_GETFL,F_SETFL | 獲取、設置文件狀態信息 |
F_DUPFD | 復制現有描述符 |
F_GETFD,F_SETFD | 獲取、設置文件描述符標志 |
F_GETOWN,F_SETOWN | 獲取、設置異步IO所有權 |
F_GETLK,F_SETLK,F_SETLKW | 獲取、設置記錄鎖 |
根據cmd的不同,可能需要傳遞額外的參數。例如,設置類的操作需要加入文件狀態信息,如O_NONBLOCK用于設置非阻塞模式。
F_DUPFD功能
在F_DUPFD中,返回新的文件描述符,可以設置新描述符的最小值。如果該值已被占用,則生成一個比該值更大的描述符。
#include <iostream> #include <unistd.h> #include <fcntl.h> using namespace std; int main() { int fd = open("example.txt", O_RDONLY|O_CREAT); if (fd == -1) { perror("open"); return 1; } int new_fd = fcntl(fd, F_DUPFD, 20); // 復制文件描述符,新描述符值大于等于10 if (new_fd == -1) { perror("fcntl"); close(fd); return 1; } printf("Original fd: %d, New fd: %dn", fd, new_fd); cout
F_GETFL和F_SETFL功能
使用F_GETFL和F_SETFL命令可以獲取和設置文件狀態標志。文件狀態標志包括O_APPEND、O_NONBLOCK等。
非阻塞:O_NONBLOCK。
#include <iostream> #include <fcntl.h> #include <unistd.h> using namespace std; void SetNoBlock(int fd){ int info=fcntl(fd,F_GETFL); if(info
結束語
至此,我們已經深入探討了計算機科學中的諸多重要概念,包括I/O操作、線程同步與互斥、文件描述符管理等。理解這些概念對于編寫高效、可靠的程序至關重要。希望本文能夠為您的學習和實踐提供有益的參考。如果您在實際編程中遇到任何問題,建議查閱相關文檔或進一步研究具體案例。感謝您的閱讀,祝您在編程的道路上不斷進步!