I O多路復用之select

2022-04-07 16:09:53 字數 2617 閱讀 3372

1、什麼是i/o多路復用

關於什麼是i/o多路復用,在知乎上有個很好的回答,可以參考羅志宇前輩的回答。

這裡記錄一下自己的理解。我認為要理解這個術語得從兩方面去出發,一是:多路是個什麼概念?二是:復用的什麼東西?先說第乙個問題。多路指的是多條獨立的i/o流,i/o流可以這麼理解:讀是一條流(稱之為讀流,比如輸入流),寫是一條流(稱之為寫流,比如輸出流),異常也是一條流(稱之為異常流),每條流用乙個檔案描述符來表示,同乙個檔案描述符可以同時表示讀流和寫流。再來看第二個方面,復用的是什麼東西?復用的是執行緒,復用執行緒來跟蹤每路io的狀態,然後用乙個執行緒就可以處理所有的io。

當然,不提什麼i/o多路復用也能在乙個執行緒就處理完所有的io流,用個while迴圈挨個處理一次不就解決了嘛?那為什麼還要提出這個技術呢?原因就是剛才我們想的方法(輪詢)效率太低了,資源利用率也不高。試想一下,如果某個io被設定成了阻塞io,那麼其他的io將被卡死,也就浪費掉了其他的io資源。另一方面,假設所有io被設定成非阻塞,那cpu一天到晚也不用幹別的事了,就在這不停的問,現在可以進行io操作了嗎,直到有乙個裝置準備好環境才能進行io,也就是在裝置準備io環境的這一段時間,cpu是沒必要瞎問的,問了也沒結果。

隨後硬體發展起來了,有了多核的概念,也就有了多執行緒。這個時候可以這樣做,來一條io我開乙個執行緒,這樣的話再也不用輪詢了。然而,管理執行緒是要耗費系統資源的,程式設計師也開始頭疼了,執行緒之間的互動是十分麻煩的。這樣一來程式的複雜性蹭蹭蹭地往**,io效率是可能提高了,但是軟體的開發效率卻可能減低了。

#include<sys/select.h>

intselect(int

nfds, fd_set

*readfds, fd_set

*writefds, fd_set

*exceptfds,

struct

timeval

*timeout);

struct timeval

timeout有三種取值:

如果非得與「多路」這個詞關聯起來,那就是readfds+writefds+exceptfds的數量和就是路數。

另外,還有一組與fd_set 有關的操作

select的實現依賴於裝置的驅動函式poll,poll的功能是檢查裝置的哪條條流可用(乙個裝置一般有三條流,讀流,寫流,裝置發生異常的異常流),如果其中一條流可用,返回乙個mask(表示可用的流),如果不可用,把當前程序加入裝置的流等待佇列中,例如讀等待佇列、寫等待佇列,並返回資源不可用。

select正是利用了poll的這個功能,首先讓程式設計師告知自己關心哪些io流(用檔案描述符表示,也就是上文的readfds、writefds和exceptfds),並讓程式設計師告知自己這些流的範圍(也就是上文的nfds引數)以及程式的容忍度(timeout引數),然後select會把她們拷貝到核心,在核心中逐個呼叫流所對應的裝置的驅動poll函式,當範圍內的所有流也就是描述符都遍歷完之後,他會檢查是否至少有乙個流發生了,如果有,就修改那三個流集合,把她們清空,然後把發生的流加入到相應的集合中,並且select返回。如果沒有,就睡眠,讓出cpu,直到某個裝置的某條流可用,就去喚醒阻塞在流上的程序,這個時候,呼叫select的程序重新開始遍歷範圍內的所有描述符。

直接看這個步驟可能會好理解些

然後補充一副select在核心中的流程圖

select的核心實現是do_select,所以下面看一下do_select的原始碼,非完整原始碼,只保留了關鍵部分

int do_select(int n, fd_set_bits *fds, s64 *timeout)

for (j = 0; j < __nfdbits; ++j, ++i, bit <<= 1)

if ((mask & pollout_set) && (out &bit))

if ((mask & pollex_set) && (ex &bit)) }}

if(res_in)

*rinp =res_in;

if(res_out)

*routp =res_out;

if(res_ex)

*rexp =res_ex;

}wait =null;

if (retval || !*timeout || signal_pending(current))//

如果retval!=0,也就是有readdfs、writedfs、execptdfs至少有乙個發生,跳出迴圈

break

;

/*以下處理timeout引數

*/__timeout =schedule_timeout(__timeout);

if (*timeout >= 0

) *timeout +=__timeout;

}__set_current_state(task_running);

return

retval;

}

I O多路復用之select

阻塞i o模型 應用程式呼叫乙個i o函式,應用程式會一直等待資料準備好。如果資料沒有準備好,就會一直等待。只有當資料準備好,從核心拷貝到使用者空間io函式才成功返回。非阻塞i o模型 把乙個套介面設定成非阻塞告訴核心,當所有的i o操作無法完成時,不要將程序睡眠,而返回乙個錯誤資訊。此時i o操作...

IO多路復用之select

1 背景知識 我們首先來看看伺服器程式設計的模型,客戶端發來的請求服務端會產生乙個程序來對其進行服務,每當來乙個客戶請求就產生乙個程序來服務,然而程序不可能無限制的產生,因此為了解決大量客戶端訪問的問題,引入了io復用技術。即 乙個程序可以同時對多個客戶請求進行服務。也就是說io復用的 介質 是程序...

I O多路復用之select

select是用於監視多個檔案描述符狀態的變化的。即用來監視檔案描述符讀 寫 異常狀態是否就緒。函式原型 int select int nfds,fd set readfds,fd set writefds,fd set exceptfds,struct timeval timeout select...