select

select 系統調用是用來讓我們的程序監視多個文件描述符(file descrīptor)的狀態變化的。程序會停在select這裏等待,直到被監視的文件描述符有某一個或多個發生了狀態改變。select()的機制中 提供一fd_set的數據結構,實際上是一long類型的數組, 每一個數組元素都能與一打開的文件描述符(不管是Socket描述符,還是其他 文件或命名管道或設備描述符)建立聯繫,建立聯繫的工作由程序員完成, 當調用select()時,由內核根據IO狀態修改fd_set的內容,由此來通知執 行了select()的進程哪一Socket或文件可讀,

select函數原型如下:int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);

函 數的最後一個參數timeout顯然是一個超時時間值,其類型是struct timeval *,即一個struct timeval結構的變量的指針,所以我們在程序裏要申明一個struct timeval tv;然後把變量tv的地址&tv傳遞給select函數。struct timeval結構如下:

struct timeval {long tv_sec; /* seconds */long tv_usec; /* microseconds */};

第2、3、4三個參數的類型是一樣的: fd_set *,即我們在程序裏要申明幾個fd_set類型的變量,比如定義了rfds, wfds, efds。

另外關於fd_set類型的變量,還有一組標準的宏定義來處理此類變量:

FD_ZERO(fd_set *fdset):清空fdset與所有文件描述符的聯繫。

FD_SET(int fd, fd_set *fdset):建立文件描述符fd與fdset的聯繫。

FD_CLR(int fd, fd_set *fdset):清除文件描述符fd與fdset的聯繫。

FD_ISSET(int fd, fd_set *fdset):檢查fd_set聯繫的文件描述符fd是否可讀寫,>0表示可讀寫。

(關 於fd_set及相關宏的定義見/usr/include/sys/types.h)定義的這三個參數都是描述符的集合,第一個rfds是用來保存這樣的 描述符的:當描述符的狀態變成可讀的時系統就會告訴select函數返回,第二個wfds是指有描述符狀態變成可寫的時系統就會告訴select函數返 回,第三個參數efds是特殊情況,即描述符上有特殊情況發生時系統會告訴select函數返回。下面以一個輸入爲例來說明:

int fd1, fd2; /* 在定義兩個描述符*/

fd1 = socket(...); /* 創建socket連接*/

fd2 = open(“/dev/tyS0”,O_RDWR); /* 打開一個串口*/

FD_ZERO(&rfds); /* 用select函數之前先把集合清零 */

FD_SET(fd1, &rfds); /* 分別把2個描述符加入讀監視集合裏去 */

FD_SET(fd2, &rfds);

int maxfd = 0;

maxfd = (fd1>fd2)?(fd1+1):(fd2+1); /* 注意是最大值還要加1 */

ret = select(maxfd, &rfds, NULL, NULL, &tv); /*然後調用select函數*/

這樣就可以使用一個開關語句(switch語句)來判斷到底是哪一個輸入源在輸入數據。具體判斷如下:

switch(ret){

case -1:perror("select");/* 這說明select函數出錯 */

case 0:printf("超時\n"); /* 說明在設定的時間內,socket的狀態沒有發生變化 */

default:

if(FD_ISSET(fd1, &rfds)) 處理函數1();/*socket有數據來*/

if(FD_ISSET(fd2, &rfds)) 處理函數2();/*ttyS0有數據來*/

}

以下來自網絡搜索:

Linux下select調用的過程:

1.用戶層應用程序調用select(),底層調用poll())

2.核心層調用sys_select() ------> do_select()

最終調用文件描述符fd對應的struct file類型變量的struct file_operations *f_op的poll函數。

poll指向的函數返回當前可否讀寫的信息。

1)如果當前可讀寫,返回讀寫信息。

2)如果當前不可讀寫,則阻塞進程,並等待驅動程序喚醒,重新調用poll函數,或超時返回。

3.驅動需要實現poll函數。

當驅動發現有數據可以讀寫時,通知核心層,核心層重新調用poll指向的函數查詢信息。

poll_wait(filp,&wait_q,wait) // 此處將當前進程加入到等待隊列中,但並不阻塞

在中斷中使用wake_up_interruptible(&wait_q)喚醒等待隊列

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章