|  | ||||||||||||||||||||||||||||||||||||||||
| Linux下多路復用I/O接口 | ||||||||||||||||||||||||||||||||||||||||
| 多路復用 1.函數說明 前面的(de)fcntl()函數解(jie)決了文件的(de)共(gong)享問題,接下(xia)來該(gai)處理I/O復用的(de)情(qing)況了。 總的(de)來說,I/O處理的(de)模(mo)型有5種。     ● 阻塞I/O模型:在這種模型下,若所調用的I/O函數沒有完成相關的功能,則會使進程掛起,直到相關數據到達才會返回。如常見對管道設備、終端設備和網絡設備進行讀寫時經常會出現這種情況。 它是(shi)(shi)非阻塞(sai)的。當有就緒的數(shu)據(ju)(ju)時(shi),內核就向該進程(cheng)發送SIGIO信號。 無論我們如何(he)處理SIGIO信號,這種模型的好處是(shi)(shi)當等待數(shu)據(ju)(ju)到(dao)(dao)達時(shi),可(ke)以(yi)不(bu)阻塞(sai)。主程(cheng)序繼(ji)續(xu)執行,只(zhi)有收到(dao)(dao)SIGIO信號時(shi)才(cai)去處理數(shu)據(ju)(ju)即(ji)可(ke)。 ● 異步(bu)I/O模型(xing):在(zai)這種模型(xing)下,進程(cheng)先讓(rang)內(nei)核(he)啟動I/O操(cao)(cao)作(zuo),并在(zai)整個(ge)操(cao)(cao)作(zuo)完成后通(tong)知該進程(cheng)。這種模型(xing)與信(xin)號(hao)驅動模型(xing)的主要區別在(zai)于:信(xin)號(hao)驅動I/O是由內(nei)核(he)通(tong)知我(wo)們何(he)時可以啟動一個(ge)I/O操(cao)(cao)作(zuo),而異步(bu)I/O模型(xing)是由內(nei)核(he)通(tong)知進程(cheng)I/O操(cao)(cao)作(zuo)何(he)時完成的。現在(zai),并不是所有(you)的系統(tong)都支持(chi)這種模型(xing)。 可(ke)以看到(dao)(dao),select()和(he)poll()的(de)I/O多路(lu)轉接模型是處理(li)I/O復用的(de)一(yi)個(ge)(ge)高效(xiao)的(de)方法。它(ta)可(ke)以具體設置程序中每一(yi)個(ge)(ge)所關心的(de)文件(jian)(jian)描述(shu)符的(de)條件(jian)(jian)、希望等(deng)待(dai)的(de)時(shi)間等(deng),從select()和(he)poll()函(han)數返回時(shi),內(nei)核會(hui)通(tong)知用戶(hu)已(yi)準備好的(de)文件(jian)(jian)描述(shu)符的(de)數量、已(yi)準備好的(de)條件(jian)(jian)(或事件(jian)(jian))等(deng)。通(tong)過(guo)使用select()和(he)poll()函(han)數的(de)返回結(jie)果(可(ke)能是檢測(ce)到(dao)(dao)某(mou)個(ge)(ge)文件(jian)(jian)描述(shu)符的(de)注冊事件(jian)(jian)或是超時(shi),或是調用出錯),就可(ke)以調用相應(ying)的(de)I/O處理(li)函(han)數了(le)。 2.函(han)數格(ge)式   select()函數的語法要(yao)點(dian)如表(biao)2.8所示。 表2.8 select()函(han)數語(yu)法要點(dian) 
  可(ke)以看到(dao),select()函數根據希望進行的(de)文件(jian)(jian)操作對文件(jian)(jian)描述符進行了分類處理,這里對文件(jian)(jian)描述符的(de)處理主要涉(she)及4個宏函數,如表(biao)2.9所示。 表2.9 select()文件描述符處理函數 
 一般(ban)來(lai)(lai)說(shuo),在(zai)每(mei)次(ci)使(shi)用(yong)(yong)select()函(han)數之前,首先使(shi)用(yong)(yong)FD_ZERO()和(he)FD_SET()來(lai)(lai)初始化(hua)文件描(miao)(miao)述(shu)(shu)符(fu)(fu)(fu)集(ji)(ji)(在(zai)需要重(zhong)復調用(yong)(yong)select()函(han)數時(shi),先把一次(ci)初始化(hua)好的文件描(miao)(miao)述(shu)(shu)符(fu)(fu)(fu)集(ji)(ji)備份(fen)下來(lai)(lai),每(mei)次(ci)讀取它即可)。在(zai)select()函(han)數返(fan)回后(hou),可循環使(shi)用(yong)(yong)FD_ISSET()來(lai)(lai)測試描(miao)(miao)述(shu)(shu)符(fu)(fu)(fu)集(ji)(ji),在(zai)執(zhi)行完對(dui)相關文件描(miao)(miao)述(shu)(shu)符(fu)(fu)(fu)的操作后(hou),使(shi)用(yong)(yong)FD_CLR()來(lai)(lai)清(qing)除描(miao)(miao)述(shu)(shu)符(fu)(fu)(fu)集(ji)(ji)。 另外,select()函數中的timeout是一個struct timeval類型的指針(zhen),該結構體(ti)如下(xia)所示:     struct timeval      可以看到,這個時間結構體的精確度可以設置到微秒級,這對于大多數的應用而言已經足夠了。 表2.10 poll()函數語法要點 
 3.使(shi)用實例(li) 當使(shi)用select()函數(shu)時,存在一系列的(de)問題,例如,內核必須檢查多余(yu)的(de)文(wen)(wen)件(jian)描(miao)述符(fu),每(mei)次調用select()之后必須重置被監(jian)聽的(de)文(wen)(wen)件(jian)描(miao)述符(fu)集,而且可監(jian)聽的(de)文(wen)(wen)件(jian)個數(shu)受限(xian)制(使(shi)用FD_SETSIZE宏來表(biao)示(shi)fd_set結構能夠容納(na)的(de)文(wen)(wen)件(jian)描(miao)述符(fu)的(de)大數(shu)目)等。實際上,poll機(ji)制與select機(ji)制相比(bi)效率更高(gao),使(shi)用范圍(wei)更廣。下面以poll()函數(shu)為(wei)例實現某種功能。 本實例中(zhong)主(zhu)要(yao)實現通過(guo)調用poll()函數來監(jian)聽三(san)個終端的(de)(de)(de)輸(shu)入(分別重定向到(dao)兩(liang)個管(guan)道文(wen)(wen)(wen)件的(de)(de)(de)虛(xu)擬終端及(ji)主(zhu)程(cheng)序(xu)所運行的(de)(de)(de)虛(xu)擬終端)并分別進(jin)行相應的(de)(de)(de)處理(li)。在這里我(wo)們建立了一個poll()函數監(jian)視(shi)的(de)(de)(de)讀(du)文(wen)(wen)(wen)件描(miao)(miao)述(shu)符(fu)(fu)(fu)集,其(qi)中(zhong)包含三(san)個文(wen)(wen)(wen)件描(miao)(miao)述(shu)符(fu)(fu)(fu),分別為標準輸(shu)入文(wen)(wen)(wen)件描(miao)(miao)述(shu)符(fu)(fu)(fu)和兩(liang)個管(guan)道文(wen)(wen)(wen)件描(miao)(miao)述(shu)符(fu)(fu)(fu)。通過(guo)監(jian)視(shi)主(zhu)程(cheng)序(xu)的(de)(de)(de)虛(xu)擬終端標準輸(shu)入來實現程(cheng)序(xu)的(de)(de)(de)控制(如程(cheng)序(xu)結束);以兩(liang)個管(guan)道作為數據輸(shu)入,主(zhu)程(cheng)序(xu)將(jiang)從兩(liang)個管(guan)道讀(du)取的(de)(de)(de)輸(shu)入字符(fu)(fu)(fu)串寫入到(dao)標準輸(shu)出文(wen)(wen)(wen)件(屏幕)。 為了充分表(biao)現poll()函(han)數的功(gong)能,在運(yun)行(xing)主(zhu)程序時,需(xu)要打開3個虛(xu)(xu)擬(ni)終端(duan):首先(xian)用mknod命令(ling)創建兩個管道in1和in2。接(jie)下來,在兩個虛(xu)(xu)擬(ni)終端(duan)上分別運(yun)行(xing)cat>in1和cat>in2。同(tong)時在第三(san)個虛(xu)(xu)擬(ni)終端(duan)上運(yun)行(xing)主(zhu)程序。 在(zai)程序運行后,如果(guo)在(zai)兩個管(guan)道終(zhong)端(duan)上輸入字(zi)符串,則可(ke)以觀察(cha)到同樣的(de)內容將在(zai)主(zhu)程序的(de)虛擬終(zhong)端(duan)上逐行顯示。 如(ru)(ru)果(guo)(guo)想結(jie)束主(zhu)程(cheng)(cheng)(cheng)序(xu),只要在(zai)主(zhu)程(cheng)(cheng)(cheng)序(xu)的(de)虛擬終端下(xia)輸入以“q”或“Q”字(zi)符開頭的(de)字(zi)符串即可(ke)。如(ru)(ru)果(guo)(guo)三個文件(jian)一(yi)直在(zai)無輸入狀(zhuang)態(tai)中,則主(zhu)程(cheng)(cheng)(cheng)序(xu)一(yi)直處于阻(zu)塞狀(zhuang)態(tai)。為(wei)了防(fang)止無限期的(de)阻(zu)塞,在(zai)程(cheng)(cheng)(cheng)序(xu)中設(she)置超(chao)時(shi)值(本(ben)實(shi)例中設(she)置為(wei)60s),當無輸入狀(zhuang)態(tai)持續到超(chao)時(shi)值時(shi),主(zhu)程(cheng)(cheng)(cheng)序(xu)主(zhu)動(dong)結(jie)束運行并退出(chu)。該程(cheng)(cheng)(cheng)序(xu)的(de)流程(cheng)(cheng)(cheng)圖如(ru)(ru)圖2.3所示(shi)。 
     /* multiplex_poll.c */  讀者(zhe)可以將以上(shang)程序交叉編譯,并下(xia)載(zai)到開發(fa)板上(shang)運(yun)行,以下(xia)是運(yun)行結果:     $ mknod in1 p 程序的超時(shi)結束結果如(ru)下:     $ ./multiplex_select 本文選自華清遠見嵌入式培訓教材《從實踐中學嵌入式Linux應用程序開發》 熱(re)點鏈接:       
         1、linux 文件鎖的實現及其應用 | ||||||||||||||||||||||||||||||||||||||||