學(xué)習(xí)手冊:Linux操作系統(tǒng)下的poll和select
計算機(jī)的發(fā)展,Linux操作系統(tǒng)越來越成為主流,你了解Linux操作系統(tǒng)系統(tǒng)么?你是Linux操作系統(tǒng)系統(tǒng)的應(yīng)用者么?本文為你詳細(xì)介紹Linux操作系統(tǒng)下的poll和select ,為你在學(xué)習(xí)Linux操作系統(tǒng)下的poll和select 時起一定的作用。
select()函數(shù)的作用
系統(tǒng)調(diào)用select和poll的后端實現(xiàn),用這兩個系統(tǒng)調(diào)用來查詢設(shè)備是否可讀寫,或是否處于某種狀態(tài)。如果poll為空,則驅(qū)動設(shè)備會被認(rèn)為即可讀又可寫,返回值是一個狀態(tài)掩碼
如何使用select()函數(shù)?
select()函數(shù)的接口主要是建立在一種叫'fd_set'類型的基礎(chǔ)上。它('fd_set') 是一組文件描述符(fd)的集合。由于fd_set類型的長度在不同平臺上不同,因此應(yīng)該用一組標(biāo)準(zhǔn)的宏定義來處理此類變量:
- fd_set set;
- FD_ZERO(&set); /* 將set清零 */
- FD_SET(fd, &set);/* 將fd加入set */
- FD_CLR(fd, &set);/* 將fd從set中清除 */
- FD_ISSET(fd, &set); /* 如果fd在set中則真 */
在過去,一個fd_set通常只能包含少于等于32個文件描述符,因為fd_set其實只用了一個int的比特矢量來實現(xiàn),在大多數(shù)情況下,檢查 fd_set能包括任意值的文件描述符是系統(tǒng)的責(zé)任,但確定你的fd_set到底能放多少有時你應(yīng)該檢查/修改宏FD_SETSIZE的值。*這個值是系統(tǒng)相關(guān)的*,同時檢查你的系統(tǒng)中的select() 的man手冊。有一些系統(tǒng)對多于1024個文件描述符的支持有問題。[譯者注: Linux操作系統(tǒng)就是這樣的系統(tǒng)!你會發(fā)現(xiàn)sizeof(fd_set)的結(jié)果是128(*8 = FD_SETSIZE=1024) 盡管很少你會遇到這種情況。]
select的基本接口十分簡單:
- int select(int nfds, fd_set *readset, fd_set *writeset,
- fd_set *exceptset, struct timeval *timeout);
其中:
nfds
需要檢查的文件描述符個數(shù),數(shù)值應(yīng)該比是三組fd_set中***數(shù)
更大,而不是實際文件描述符的總數(shù)。
readset
用來檢查可讀性的一組文件描述符。
writeset
用來檢查可寫性的一組文件描述符。
exceptset
用來檢查意外狀態(tài)的文件描述符。(注:錯誤并不是意外狀態(tài))
timeout
NULL指針代表無限等待,否則是指向timeval結(jié)構(gòu)的指針,代表最
長等待時間。(如果其中tv_sec和tv_usec都等于0, 則文件描述符
的狀態(tài)不被影響,但函數(shù)并不掛起)
函數(shù)將返回響應(yīng)操作的對應(yīng)操作文件描述符的總數(shù),且三組數(shù)據(jù)均在恰當(dāng)位置被修改,只有響應(yīng)操作的那一些沒有修改。接著應(yīng)該用FD_ISSET宏來查找返回的文件描述符組。
這里是一個簡單的測試單個文件描述符可讀性的例子:
- int isready(int fd)
- {
- int rc;
- fd_set fds;
- struct timeval tv;
- FD_ZERO(&fds);
- FD_SET(fd,&fds);
- // tvtv.tv_sec = tv.tv_usec = 0;
- //rc = select(fd+1, &fds, NULL, NULL, &tv);
- rc = select(fd+1, &fds, NULL, NULL, NULL);
- if (rc < 0)
- return -1;
- return FD_ISSET(fd,&fds) ? 1 : 0;
- }
當(dāng)然如果我們把NULL指針作為fd_set傳入的話,這就表示我們對這種操作的發(fā)生不感興趣,但select() 還是會等待直到其發(fā)生或者超過等待時間。
[譯者注:在Linux操作系統(tǒng)中,timeout指的是程序在非sleep狀態(tài)中度過的時間,而不是實際上過去的時間,這就會引起和非Linux操作系統(tǒng)平臺移植上的時間不等問題。移植問題還包括在System V風(fēng)格中select()在函數(shù)退出前會把timeout設(shè)為未定義的 NULL狀態(tài),而在BSD中則不是這樣, Linux操作系統(tǒng)在這點上遵從System V,因此在重復(fù)利用timeout指針問題上也應(yīng)該注意。]
Linux操作系統(tǒng)下select調(diào)用的過程:
1.用戶層應(yīng)用程序調(diào)用select(),底層調(diào)用poll())
2.核心層調(diào)用sys_select() ------> do_select()
最終調(diào)用文件描述符fd對應(yīng)的struct file類型變量的struct file_operations *f_op的poll函數(shù)。
poll指向的函數(shù)返回當(dāng)前可否讀寫的信息。
1)如果當(dāng)前可讀寫,返回讀寫信息。
2)如果當(dāng)前不可讀寫,則阻塞進(jìn)程,并等待驅(qū)動程序喚醒,重新調(diào)用poll函數(shù),或超時返回。
3.驅(qū)動需要實現(xiàn)poll函數(shù)。
當(dāng)驅(qū)動發(fā)現(xiàn)有數(shù)據(jù)可以讀寫時,通知核心層,核心層重新調(diào)用poll指向的函數(shù)查詢信息。
poll_wait(filp,&wait_q,wait) // 此處將當(dāng)前進(jìn)程加入到等待隊列中,但并不阻塞
在中斷中使用wake_up_interruptible(&wait_q)喚醒等待隊列
希望本文對你學(xué)習(xí)Linux操作系統(tǒng)下的poll和select有所幫助。
【編輯推薦】