【i.MX6ULL】驅(qū)動(dòng)開發(fā)10——阻塞&非阻塞式按鍵檢測

上篇文章:介紹了linux中的五種I/O模型,本篇,就來使用阻塞式I/O和非用阻塞式I/O 是否降低。
1 阻塞I/O方式的按鍵檢測
1.1 阻塞I/O之等待隊(duì)列
阻塞訪問最大的好處就是當(dāng)設(shè)備文件不可操作的時(shí)候進(jìn)程可以進(jìn)入休眠態(tài),這樣可以將CPU資源讓出來。但是,當(dāng)設(shè)備文件可以操作的時(shí)候就必須喚醒進(jìn)程,一般在中斷函數(shù)里面完成喚醒工作。Linux 內(nèi)核提供了等待隊(duì)列(wait queue)來實(shí)現(xiàn)阻塞進(jìn)程的喚醒工作。
等待隊(duì)列頭使用結(jié)構(gòu)體wait_queue_head_t 表示:
使用 init_waitqueue_head 函數(shù)初始化等待隊(duì)列頭:
當(dāng)設(shè)備不可用的時(shí), 將這些進(jìn)程對應(yīng)的等待隊(duì)列項(xiàng)(wait_queue_t )添加到等待隊(duì)列里面:
使用宏 DECLARE_WAITQUEUE 定義并初始化一個(gè)等待隊(duì)列項(xiàng):
DECLARE_WAITQUEUE(name, tsk)
當(dāng)設(shè)備不可訪問的時(shí)候就需要將進(jìn)程對應(yīng)的等待隊(duì)列項(xiàng)添加到前面創(chuàng)建的等待隊(duì)列頭中:
當(dāng)設(shè)備可以訪問以后再將進(jìn)程對應(yīng)的等待隊(duì)列項(xiàng)從等待隊(duì)列頭中刪除即可:
當(dāng)設(shè)備可以使用的時(shí)候就要喚醒進(jìn)入休眠態(tài)的進(jìn)程:
1.2 ?阻塞I/O程序編寫
這里僅介紹與之前按鍵程序的主要區(qū)別。
1.2.1驅(qū)動(dòng)程序
阻塞讀取邏輯如下,首先要定義一個(gè)等待隊(duì)列,當(dāng)按鍵沒有按下時(shí),就要阻塞等待了(將等待隊(duì)列添加到等待隊(duì)列頭),然后進(jìn)行行一次任務(wù)切換,交出CPU的使用權(quán)。等待有按鍵按下時(shí),會(huì)有信號喚醒該等待,并將按鍵值返回給應(yīng)用層的程序。
按鍵的定時(shí)器去抖邏輯中的,讀取到按鍵后,觸發(fā)喚醒,這里以其中的一個(gè)按鍵為例,其邏輯如下:
1.2.2 應(yīng)用程序
應(yīng)用程序不需要修改,還使用之前的輪詢讀取的方式,為了在測試時(shí)看出阻塞與非阻塞方式的區(qū)別,在read函數(shù)前后添加打印,如果程序運(yùn)行正常,會(huì)先打印read前一句的打印,直到有按鍵按下后,read函數(shù)才被接觸阻塞,read后一句的打印才會(huì)打印出。
1.2 實(shí)驗(yàn)
和之前一樣,使用Makefile編譯驅(qū)動(dòng)程序和應(yīng)用程序,并復(fù)制到nfs根文件系統(tǒng)中。
開始測試,按如下圖,當(dāng)沒有按鍵按下時(shí),應(yīng)用程序被阻塞:

按鍵程序在后臺運(yùn)行,此時(shí)使用top指令開查看CPU的使用率,可以發(fā)現(xiàn)阻塞式按鍵驅(qū)動(dòng)這種方式,CPU的暫用率幾乎為0,雖然按鍵應(yīng)用程序中仍實(shí)現(xiàn)循環(huán)讀取的方式,但因平時(shí)讀取不到按鍵值,按鍵應(yīng)用程序被阻塞住了,CPU的使用權(quán)被讓出,自然CPU的使用率就降下來了。

2 非阻塞I/O方式的按鍵檢測
按鍵應(yīng)用程序以非阻塞的方式讀取,按鍵驅(qū)動(dòng)程序也要以非阻塞的方式立即返回。應(yīng)用程序可以通過select、poll或epoll函數(shù)來 查詢設(shè)備是否可以操作,驅(qū)動(dòng)程序使用poll函數(shù)。
2.1 非阻塞I/O之select/poll
select函數(shù)原型:
其中超時(shí)時(shí)間使用結(jié)構(gòu)體timeval表示:
當(dāng)timeout為NULL的時(shí)候就表示無限等待。
poll函數(shù)原型:
2.2 ?非阻塞I/O程序編寫
2.2.1 驅(qū)動(dòng)程序
poll函數(shù)處理部分:
read函數(shù)處理部分:
2.2.2 應(yīng)用程序
2.2.2.1 poll方式讀取
注意open函數(shù)的參數(shù)是O_NONBLOCK,即非阻塞訪問,并且為了在測試時(shí)看出阻塞讀取與非阻塞讀取的區(qū)別,在poll函數(shù)前后添加打印,如果程序正常運(yùn)行,poll函數(shù)則不會(huì)被阻塞,500ms超時(shí)未讀取到按鍵值后會(huì)再次循環(huán)讀取,實(shí)際效果就是可以看打一直有打印輸出。
? ?
2.2.2.2 select方式讀取
select方式讀取與poll方式類似,都是非阻塞讀取,程序類似:
2.3 實(shí)驗(yàn)
2.3.1 poll方式讀取
和之前一樣,使用Makefile編譯驅(qū)動(dòng)程序和應(yīng)用程序,并復(fù)制到nfs根文件系統(tǒng)中。
開始測試,按如下圖,當(dāng)沒有按鍵按下時(shí),應(yīng)用程序也沒有被阻塞,從不斷的打印就可以看出應(yīng)用程序在循環(huán)運(yùn)行。當(dāng)有按鍵按下時(shí),能夠讀取到對應(yīng)的按鍵值。

按鍵程序在后臺運(yùn)行,此時(shí)使用top指令開查看CPU的使用率,可以發(fā)現(xiàn)非阻塞式按鍵驅(qū)動(dòng)這種方式,CPU的暫用率也幾乎為0,雖然按鍵應(yīng)用程序中仍實(shí)現(xiàn)循環(huán)讀取的方式,但poll函數(shù)有500ms的超時(shí)設(shè)置,在超時(shí)等待的時(shí)間里,CPU的使用權(quán)也是被讓出,所以CPU的使用率也降下來了。

2.3.2 select方式讀取
select方式讀取與poll方式讀取的效果一樣。
使用ps指令查看poll方式的按鍵進(jìn)行號,使用kill殺帶該進(jìn)程,再運(yùn)行select方式的按鍵應(yīng)用程序:

select非阻塞讀取的方式,CPU的暫用率也幾乎為0:

3 總結(jié)
本篇使用兩種I/O模型進(jìn)行按鍵讀取:阻塞式I/O和非用阻塞式I/O