Linux系統程式設計 IO多路復用之select

2021-09-29 11:54:35 字數 3366 閱讀 3872

i/o 多路復用技術是為了解決程序或執行緒阻塞到某個 i/o 系統呼叫而出現的技術,使程序不阻塞於某個特定的 i/o 系統呼叫。

select(),poll(),epoll()都是i/o多路復用的機制。i/o多路復用通過一種機制,可以監視多個描述符,一旦某個描述符就緒(一般是讀就緒或者寫就緒,就是這個檔案描述符進行讀寫操作之前),能夠通知程式進行相應的讀寫操作。但select(),poll(),epoll()本質上都是同步i/o,因為他們都需要在讀寫事件就緒後自己負責進行讀寫,也就是說這個讀寫過程是阻塞的,而非同步i/o則無需自己負責進行讀寫,非同步i/o的實現會負責把資料從核心拷貝到使用者空間。

與多執行緒和多程序相比,i/o 多路復用的最大優勢是系統開銷小,系統不需要建立新的程序或者執行緒,也不必維護這些執行緒和程序。

#include

intselect

(int nfds, fd_set *readfds, fd_set *writefds,

fd_set *exceptfds,

struct timeval *timeout)

;功能:

監視並等待多個檔案描述符的屬性變化(可讀、可寫或錯誤異常)。

select

()函式監視的檔案描述符分 3 類,分別是writefds、readfds、和 exceptfds。

呼叫後 select

() 函式會阻塞,直到有描述符就緒(有資料可讀、可寫、或者有錯誤異常),

或者超時( timeout 指定等待時間),函式才返回。

當 select

()函式返回後,可以通過遍歷 fdset,來找到就緒的描述符。

引數: nfds: 要監視的檔案描述符的範圍,一般取監視的描述符數的最大值+

1,如這裡寫 10,

這樣的話,描述符 0,1

,2 …… 9 都會被監視,在 linux 上最大值一般為1024。

readfd: 監視的可讀描述符集合,只要有檔案描述符即將進行讀操作,這個檔案描述符就儲存到這。

writefds: 監視的可寫描述符集合。

exceptfds: 監視的錯誤異常描述符集合。

timeout: 超時時間,它告知核心等待所指定描述字中的任何乙個就緒可花多少時間。

其 timeval 結構用於指定這段時間的秒數和微秒數。

返回值:

成功:就緒描述符的數目,超時返回 0,

出錯:-

1timeout引數有三種可能:

1)永遠等待下去:僅在有乙個描述字準備好 i/o 時才返回。為此,把該引數設定為空指標 null。

在有乙個描述字準備好 i/o 時返回,如果時間到了,就算沒有檔案描述符發生變化,

這個函式會返回 0。

3)根本不等待(不阻塞):檢查描述字後立即返回,這稱為輪詢。

為此,struct timeval變數的時間值指定為 0 秒 0 微秒,

檔案描述符屬性無變化返回 0,有變化返回準備好的描述符數量。

struct timeval

;

中間的三個引數 readfds、writefds 和 exceptfds 指定我們要讓核心監測讀、寫和異常條件的描述字。

如果不需要使用某乙個的條件,就可以把它設為空指標( null )。

集合fd_set 中存放的是檔案描述符,可通過以下四個巨集進行設定:

//將乙個給定的檔案描述符從集合中刪除

void

fd_clr

(int fd, fd_set *set)

;// 檢查集合中指定的檔案描述符是否可以讀寫

intfd_isset

(int fd, fd_set *set)

;//將乙個給定的檔案描述符加入集合之中

void

fd_set

(int fd, fd_set *set)

;//清空集合

void

fd_zero

(fd_set *set)

;

我們寫這麼乙個例子,同時迴圈讀取標準輸入的內容,讀取有名管道的內容,預設的情況下,標準輸入沒有內容,read()時會阻塞,同樣的,有名管道如果沒有內容,read()也會阻塞,我們如何實現迴圈讀取這兩者的內容呢?最簡單的方法是,開兩個執行緒,乙個執行緒迴圈讀標準輸入的內容,乙個執行緒迴圈讀有名管道的內容。而在這裡,我們通過 select() 函式實現這個功能:

#include

#include

#include

#include

#include

#include

intmain

(int argc,

char

*ar**)

fd =

open

("test_fifo"

, o_rdwr)

;// 讀寫方式開啟管道

if(fd <0)

ret =0;

while(1

)else

if(ret >0)

;if(fd_isset(0

,&rfds)

)elseif(

fd_isset

(fd,

&rfds))}

elseif(

0== ret)

}return0;

}

下面為上面例子的往有名管道寫內容的示例**:

#include

#include

#include

#include

#include

#include

#include

intmain

(int argc,

char

*ar**)

fd =

open

("test_fifo"

, o_rdwr)

;// 讀寫方式開啟管道

if(fd <0)

while(1

)return0;

}

select優點:

select()目前幾乎在所有的平台上支援,其良好跨平台支援也是它的乙個優點。

select的缺點

1)每次呼叫 select(),都需要把 fd 集合從使用者態拷貝到核心態,這個開銷在 fd 很多時會很大,同時每次呼叫 select() 都需要在核心遍歷傳遞進來的所有 fd,這個開銷在 fd 很多時也很大。

2)單個程序能夠監視的檔案描述符的數量存在最大限制,在 linux 上一般為 1024,可以通過修改巨集定義甚至重新編譯核心的方式提公升這一限制,但是這樣也會造成效率的降低。

Linux系統程式設計 IO多路復用之poll

select 和 poll 系統呼叫的本質一樣,前者在 bsd unix 中引入的,後者在 system v 中引入的。poll 的機制與 select 類似,與 select 在本質上沒有多大差別,管理多個描述符也是進行輪詢,根據描述符的狀態進行處理,但是 poll 沒有最大檔案描述符數量的限制 ...

I O多路復用

一 五種i o模型 1 阻塞i o模型 最流行的i o模型是阻塞i o模型,預設情形下,所有套介面都是阻塞的。我們以資料報套介面為例來講解此模型 我們使用udp而不是tcp作為例子的原因在於就udp而言,資料準備好讀取的概念比較簡單 要麼整個資料報已經收到,要麼還沒有。然而對於tcp來說,諸如套介面...

i o多路復用

最常見的i o多路復用就是 select poll epoll了,下面說說他們的一些特點和區別吧。select 可讀 可寫 異常三種檔案描述符集的申明和初始化。fd set readfds,writefds,exceptionfds fd zero readfds fd zero writefds ...