操作系統(tǒng)之IO模型

一、相關(guān)概念

1.1 同步與異步胞皱、阻塞與非阻塞

  • 同步和異步:用戶程序通過recv()進(jìn)行系統(tǒng)調(diào)用后,如果最后還需要調(diào)用read()骨望,則是同步的牵囤;否則就是異步的爸黄。

  • 阻塞和非阻塞:用戶程序通過recv()進(jìn)行系統(tǒng)調(diào)用后滞伟,如果還可以做其它事情,則是非阻塞的炕贵,反之則是阻塞的梆奈。

概念有些抽象,可以通過以下的例子來理解一下這組概念:

假設(shè)小明需要在網(wǎng)上下載一個(gè)軟件:

  • 同步阻塞:如果小明點(diǎn)擊下載按鈕之后称开,就一直干瞪著進(jìn)度條不做其他任何事情直到軟件下載完成鉴裹;
  • 異步阻塞(比較罕見):如果小明點(diǎn)擊下載按鈕之后,不用瞪著進(jìn)度條但也不做其他任何事情直到軟件下載完成钥弯,軟件下載完成是會(huì)「叮」的一聲通知的督禽。
  • 同步非阻塞:如果小明點(diǎn)擊下載按鈕之后脆霎,就去做其他事情了,不過他總需要時(shí)不時(shí)瞄一眼屏幕看軟件是不是下載完成了
  • 異步非阻塞:如果小明點(diǎn)擊下載按鈕之后狈惫,就去做其他事情了睛蛛,軟件下載完之后「叮」的一聲通知小明胧谈,小明再回來繼續(xù)處理下載完的軟件

1.2 用戶態(tài)和內(nèi)核態(tài)

1.2.1 用戶態(tài)和內(nèi)核態(tài)的基本概念

  • 用戶態(tài):就是提供應(yīng)用程序運(yùn)行的空間忆肾,為了使應(yīng)用程序訪問到內(nèi)核管理的資源例如CPU,內(nèi)存菱肖,I/O客冈。
  • 內(nèi)核態(tài):控制計(jì)算機(jī)的硬件資源,例如協(xié)調(diào)CPU資源稳强,分配內(nèi)存資源场仲,并且提供穩(wěn)定的環(huán)境供應(yīng)用程序運(yùn)行。
用戶空間和內(nèi)核空間

1.2.2 用戶態(tài)切換到內(nèi)核態(tài)的方式

  • 中斷:當(dāng)外設(shè)完成用戶的請求時(shí)退疫,會(huì)向CPU發(fā)送中斷信號(hào)渠缕。
  • 異常:如果當(dāng)前進(jìn)程運(yùn)行在用戶態(tài),如果這個(gè)時(shí)候發(fā)生了異常事件褒繁,就會(huì)觸發(fā)切換亦鳞。例如:缺頁異常。
  • 系統(tǒng)調(diào)用:本質(zhì)上也是中斷棒坏,屬于軟中斷的一種燕差。

1.3 文件描述符

內(nèi)核(kernel)利用文件描述符(file descriptor)來訪問文件。文件描述符是非負(fù)整數(shù)俊抵。打開現(xiàn)存文件或新建文件時(shí)谁不,內(nèi)核會(huì)返回一個(gè)文件描述符。讀寫文件也需要使用文件描述符來指定待讀寫的文件徽诲。

二刹帕、IO模型

2.1 同步阻塞IO

  • 應(yīng)用進(jìn)程向內(nèi)核發(fā)起recfrom讀取數(shù)據(jù)吵血。

  • 準(zhǔn)備數(shù)據(jù)報(bào)(應(yīng)用進(jìn)程阻塞)。

  • 將數(shù)據(jù)從內(nèi)核負(fù)責(zé)到應(yīng)用空間偷溺。

  • 復(fù)制完成后蹋辅,返回成功提示。

同步阻塞IO

2.2 同步非阻塞IO

  • 應(yīng)用進(jìn)程向內(nèi)核發(fā)起recvfrom讀取數(shù)據(jù)挫掏。
  • 沒有數(shù)據(jù)報(bào)準(zhǔn)備好侦另,即刻返回EWOULDBLOCK錯(cuò)誤碼。
  • 應(yīng)用進(jìn)程向內(nèi)核發(fā)起recvfrom讀取數(shù)據(jù)尉共。
  • 已有數(shù)據(jù)包準(zhǔn)備好就進(jìn)行一下 步驟褒傅,否則還是返回錯(cuò)誤碼。
  • 將數(shù)據(jù)從內(nèi)核拷貝到用戶空間袄友。
  • 完成后殿托,返回成功提示。
同步非阻塞IO

2.3 IO多路復(fù)用

定義:單線程或單進(jìn)程同時(shí)監(jiān)測若干個(gè)文件描述符是否可以執(zhí)行IO操作的能力剧蚣,linux有三種實(shí)現(xiàn)方式支竹,分別為select,poll和epoll。

IO多路復(fù)用

2.3.1 select

  • 源碼

/* According to POSIX.1-2001, POSIX.1-2008 */
    #include <sys/select.h>
    /* According to earlier standards */
    #include <sys/time.h>
    #include <sys/types.h>
    #include <unistd.h>

    int select(int nfds, fd_set *readfds, fd_set *writefds,
                fd_set *exceptfds, struct timeval *timeout);

    int pselect(int nfds, fd_set *readfds, fd_set *writefds,
                fd_set *exceptfds, const struct timespec *timeout,
                const sigset_t *sigmask);

    void FD_CLR(int fd, fd_set *set);
    int  FD_ISSET(int fd, fd_set *set);
    void FD_SET(int fd, fd_set *set);
    void FD_ZERO(fd_set *set);

select的調(diào)用會(huì)阻塞到有文件描述符可以進(jìn)行IO操作或被信號(hào)打斷或者超時(shí)才會(huì)返回鸠按。

select將監(jiān)聽的文件描述符分為三組礼搁,每一組監(jiān)聽不同的需要進(jìn)行的IO操作。readfds是需要進(jìn)行讀操作的文件描述符目尖,writefds是需要進(jìn)行寫操作的文件描述符馒吴,exceptfds是需要進(jìn)行異常事件處理的文件描述符。這三個(gè)參數(shù)可以用NULL來表示對應(yīng)的事件不需要監(jiān)聽瑟曲。

當(dāng)select返回時(shí)募书,每組文件描述符會(huì)被select過濾,只留下可以進(jìn)行對應(yīng)IO操作的文件描述符测蹲。

FD_xx系列的函數(shù)是用來操作文件描述符組和文件描述符的關(guān)系莹捡。

FD_ZERO用來清空文件描述符組。每次調(diào)用select前都需要清空一次扣甲。

select可同時(shí)監(jiān)聽的文件描述符數(shù)量是通過FS_SETSIZE來限制的篮赢,在Linux系統(tǒng)中,該值為1024琉挖。

2.3.2 poll

  • 源碼
#include <poll.h>

    int poll(struct pollfd *fds, nfds_t nfds, int timeout);

    #include <signal.h>
    #include <poll.h>

    int ppoll(struct pollfd *fds, nfds_t nfds,
            const struct timespec *tmo_p, const sigset_t *sigmask);

    struct pollfd {
        int fd; /* file descriptor */
        short events; /* requested events to watch */
        short revents; /* returned events witnessed */
    };

poll和select用三組文件描述符不同的是启泣,poll只有一個(gè)pollfd數(shù)組,數(shù)組中的每個(gè)元素都表示一個(gè)需要監(jiān)聽IO操作事件的文件描述符示辈。events參數(shù)是我們需要關(guān)心的事件寥茫,revents是所有內(nèi)核監(jiān)測到的事件。

poll在linux下沒有監(jiān)聽的文件描述符數(shù)量限制矾麻,但是如果過多的話纱耻,速度也會(huì)變慢芭梯。

2.3.3 epoll

  • 源碼
#include <sys/epoll.h>

    int epoll_create(int size);
    int epoll_create1(int flags);

    int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

    int epoll_wait(int epfd, struct epoll_event *events,
                int maxevents, int timeout);
    int epoll_pwait(int epfd, struct epoll_event *events,
                int maxevents, int timeout,
                const sigset_t *sigmask);

epoll_create用于創(chuàng)建一個(gè)epoll實(shí)例,而epoll_ctl用于往epoll實(shí)例中增刪改要監(jiān)測的文件描述符弄喘,epoll_wait則用于阻塞的等待可以執(zhí)行IO操作的文件描述符直到超時(shí)玖喘。

epoll優(yōu)于select&poll在下面幾點(diǎn):

  • 在需要同時(shí)監(jiān)聽的文件描述符數(shù)量增加時(shí),select&poll是O(N)的復(fù)雜度蘑志,epoll是O(1)累奈,在N很小的情況下,差距不會(huì)特別大急但,但如果N很大的前提下澎媒,一次O(N)的循環(huán)可要比O(1)慢很多,所以高性能的網(wǎng)絡(luò)服務(wù)器都會(huì)選擇epoll進(jìn)行IO多路復(fù)用波桩。
  • epoll內(nèi)部用一個(gè)文件描述符掛載需要監(jiān)聽的文件描述符旱幼,這個(gè)epoll的文件描述符可以在多個(gè)線程/進(jìn)程共享,所以epoll的使用場景要比select&poll要多突委。

2.4 異步IO

進(jìn)程發(fā)起read操作之后,立刻就可以開始去做其它的事冬三。而另一方面匀油,從kernel的角度,當(dāng)它受到一個(gè)asynchronous read之后勾笆,首先它會(huì)立刻返回敌蚜,所以不會(huì)對用戶進(jìn)程產(chǎn)生任何block。然后窝爪,kernel會(huì)等待數(shù)據(jù)準(zhǔn)備完成弛车,然后將數(shù)據(jù)拷貝到用戶內(nèi)存,當(dāng)這一切都完成之后蒲每,kernel會(huì)給用戶進(jìn)程發(fā)送一個(gè)signal纷跛,告訴它read操作完成了⊙樱  
這個(gè)模型工作機(jī)制是:告訴內(nèi)核啟動(dòng)某個(gè)操作贫奠,并讓內(nèi)核在整個(gè)操作(包括第二階段,即將數(shù)據(jù)從內(nèi)核拷貝到進(jìn)程緩沖區(qū)中)完成后通知我們望蜡。

異步IO模型
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末唤崭,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子脖律,更是在濱河造成了極大的恐慌谢肾,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件小泉,死亡現(xiàn)場離奇詭異芦疏,居然都是意外死亡冕杠,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進(jìn)店門眯分,熙熙樓的掌柜王于貴愁眉苦臉地迎上來拌汇,“玉大人,你說我怎么就攤上這事弊决≡胍ǎ” “怎么了?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵飘诗,是天一觀的道長与倡。 經(jīng)常有香客問我,道長昆稿,這世上最難降的妖魔是什么纺座? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮溉潭,結(jié)果婚禮上净响,老公的妹妹穿的比我還像新娘。我一直安慰自己喳瓣,他們只是感情好馋贤,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著畏陕,像睡著了一般配乓。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上惠毁,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天犹芹,我揣著相機(jī)與錄音,去河邊找鬼鞠绰。 笑死腰埂,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蜈膨。 我是一名探鬼主播盐固,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼丈挟!你這毒婦竟也來了刁卜?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤曙咽,失蹤者是張志新(化名)和其女友劉穎蛔趴,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體例朱,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡孝情,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年鱼蝉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片箫荡。...
    茶點(diǎn)故事閱讀 38,094評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡魁亦,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出羔挡,到底是詐尸還是另有隱情洁奈,我是刑警寧澤,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布绞灼,位于F島的核電站利术,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏低矮。R本人自食惡果不足惜印叁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望军掂。 院中可真熱鬧轮蜕,春花似錦、人聲如沸蝗锥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽玛追。三九已至,卻和暖如春闲延,著一層夾襖步出監(jiān)牢的瞬間痊剖,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工垒玲, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留陆馁,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓合愈,卻偏偏與公主長得像叮贩,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子佛析,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評論 2 345