Linux核心開發之阻塞非阻塞IO 輪詢操作

2021-06-22 08:25:44 字數 2876 閱讀 1837

「小王,來聊聊,今天面試的情況怎麼樣,應該挺順利的吧..」看著小王平淡的眉頭,我問道。

「唉,別提了,你說,我的運氣咋這差呢,面試前你不是給我講了有關阻塞的問題嗎,我見了面試官是吧,還跟他好好的用今天排隊的例子說了有關阻塞的問題,但是..」小王哀聲嘆氣地說到。

「別但是了,怎麼啦..」

「可問題是面試官壓根就沒打算問我有關阻塞的問題及解決方案,但是問我說:這樣吧,你給我說說在linux裝置驅動中有關非阻塞的方法,我這一聽,傻眼了不是,你剛好給我講的是阻塞的東西,可人家偏要問我有關非阻塞的問題,我..」小王欲哭無淚啊..

「怎麼這樣呢,算了,機會多的是,亡羊補牢,我現在就給你說說有關非阻塞的問題----linux裝置驅動程式之阻塞非阻塞io----輪詢操作」。

使用非阻塞i/o的應用程式通常會使用select()和poll()系統呼叫查詢是否可對裝置進行無阻塞的訪問,這兩個系統呼叫最終又會引發裝置驅動中的poll()函式被執行

,所以我們的問題就集中到了如何編寫裝置驅動中的poll()函式就可以了。

二話不說,先來看看裝置驅動中的poll()函式原型:

unsigned int (*poll)(struct file *filp, struct poll_table *wait);

這個函式要進行下面兩項工作。首先,對可能引起裝置檔案狀態變化的等待佇列呼叫poll_wait(),將對應的等待佇列頭新增到poll_table.然後,返回表示是否能對裝置進行無阻塞讀寫訪問的掩碼。在上面提到了乙個poll_wait()函式,它的原型:

void poll_wait(struct file *filp, wait_queue_head_t *queue, poll_table *wait);

它的作用就是把當前程序新增到wait引數指定的等待列表(poll_table)中。需要注意的是這個函式是不會引起阻塞的,呵呵,誰給它取得個名字帶wait的,給咱們添這麼多麻煩。

「等等,你先停停,你是高手,我可是菜鳥呢,你先給我說說poll_table結構吧,心裡總是想它是什麼..」小王打斷我道。

行行,說起這個結構,我也是費了一番周折,它定義在「include/linux/poll.h, line 38「,具體如下:

typedef

struct poll_table_struct poll_table; 看看,其實沒什麼吧,不要想的太複雜了

經過以上驅動程式的poll()函式應該返回裝置資源的可獲取狀態,即pollin,pollout,pollpri,pollerr,pollnval等巨集的位"或"結果.每個巨集的含義都表示裝置的一種狀態,如:
常量說明

pollin

普通或優先順序帶資料可讀

pollrdnorm

普通資料可讀

pollrdband

優先順序帶資料可讀

pollpri

高優先順序資料可讀

pollout

普通資料可寫

pollwrnorm

普通資料可寫

pollwrband

優先順序帶資料可寫

pollerr

發生錯誤

pollhup

發生掛起

pollnval

描述字不是乙個開啟的檔案

"小王,你明白了沒.."看著小王眨巴眨巴的小眼睛,我說。
"呵呵,你乾脆給我來個典型模板,行不?"小王苛求道。
行,沒問題,你現在特殊時期,我是有求必應。請看下邊:
static

unsigned

int ***_poll(struct file *filp, poll_table *wait)

"小王,這次看明白了吧,要是還看不明白,我就再給你講講使用者空間的輪詢程式設計,兩個結合起來也許好懂點,行不"。我補充道。

在使用者程式中,select()和poll()本質上是一樣的, 不同只是引入的方式不同,前者是在bsd unix中引入的,後者是在system v中引入的。用的比較廣泛的是select

系統呼叫。原型如下:

int select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptionfds, struct timeval *timeout);

其中readfs,writefds,exceptfds分別是select()監視的讀,寫和異常處理的檔案描述符集合,numfds的值是需要檢查的號碼最高的檔案描述符加1,timeout則是乙個時間上限值,超過該值後,即使仍沒有描述符準備好也會返回。

struct timeval

涉及到檔案描述符集合的操作主要有以下幾種:
1)清除乙個檔案描述符集   fd_zero(fd_set *set);
2)將乙個檔案描述符加入檔案描述符集中    fd_set(int fd,fd_set *set);
3)將乙個檔案描述符從檔案描述符集中清除  fd_clr(int fd,fd_set *set);
4)判斷檔案描述符是否被置位    fd_isset(int fd,fd_set *set);

最後我們利用上面的檔案描述符集的相關來寫個驗證新增了裝置輪詢的驅動,把上邊兩塊聯絡起來:

#include #include #include #include #include #include time.h>
#define fifo_clear 0x1

#define buffer_len 20

main()

while (1)

/*資料可寫入*/

if (fd_isset(fd, &wfds))

}} else

}

Linux阻塞和非阻塞

阻塞 休眠 呼叫是沒有獲得資源則掛起程序,被掛起的程序進入休眠狀態,呼叫的函式只有在得到結果之後才返回,程序繼續。非阻塞 休眠 是不能進行裝置操作時不掛起,或返回,或反覆查詢,直到可以進行操作為止,被呼叫的函式不會阻塞當前程序,而會立刻返回。因為阻塞的程序會進入休眠狀態,因此,必須確保有乙個地方能夠...

Linux阻塞與非阻塞

1.阻塞 block 概念 指程序或執行緒在執行裝置操作或管道,或則網路時,不能獲取到資源就被掛起,直到滿足可操作的條件後在進行操作,被掛起的程序進入休眠狀態,從執行佇列移走,直到 等待的條件滿足才繼續執行。也就是執行到某些函式時必須等待某個事件發生函式才返回。2.非阻塞 non block 程序就...

阻塞 非阻塞

阻塞和非阻塞指 的是在接收和傳送時是否等待動作完成才返回 舉例 阻塞 block 是指,你撥通某人 的 但是此人不在,於是你拿著 等他回來,其間不能再用 非阻塞 nonblock 是指,你撥通某人 的 但是此人不在,於是你結束通話 待會兒再打。至於到時候他回來沒有,只有打了 才知道。即所謂的 輪詢 ...