1. 程式人生 > >linux c中select使用技巧——計時器(轉)

linux c中select使用技巧——計時器(轉)

通過 select() 你會 使用方法 詳細信息 說明 con detail 重新

通過本文你會了解到:
1. select()原型及參數說明
2. select()應用情景
3. select()註意事項
4. select()作定時器

原型

1 int select(int nfds, fd_set *readfds, fd_set *writefds,
2                   fd_set *exceptfds, struct timeval *utimeout);

參數說明
readfds, writefds, exceptfds為所要監聽的三個描述符集:
——readfds 監聽文件描述符是否可讀,不監聽可以傳入 NULL
——writefds

監聽文件描述符是否可寫 ,不監聽可以傳入 NULL
——exceptfds 監聽文件描述符是否有異常,不監聽可以傳入 NULL
nfdsselect() 監聽的三個描述符集中描述符的最大值+1
timeout 設置超時時間
更詳細信息請參考譯文linux-select()

應用情景
select() 函數的重點在於它可以同時監控多個描述符(一般最大為1024),並且在描述符集中沒有可操作的描述符時會進入睡眠狀態。 實際應用中,若需要同時處理多個描述符的讀寫時,如果只是創建了一系列的read()write()就會導致在有些描述符沒有準備好讀寫時而被阻塞,這樣當然不是我們期望的,因此這時就需要應用select()

註意事項
這段是select()使用必須要了解和掌握的知識點,建議認真閱讀,同時可以結合後續的一些實例做分析,相信你一定能掌握select()使用方法。

  1. nfds必須被正確設置,一般取描述符集中描述符的最大值並加1。
  2. 在非必須的情況下,盡量使用不超時的select(),即將utimeout參數設置為NULL

    1 /*參數 timeout 置為 NULL*/
    2 select(nfds, &readfds, &writefds, &exceptfds, NULL);

  3. timeout的值必須在每次select()之前重新賦值,因為操作系統會修改此值。

    1
    while(1) { 2 timeout.tv_sec = 1; 3 timeout.tv_usec = 0; 4 select(nfds, &readfds, &writefds, &exceptfds, &timeout); 5 }

  4. 由於select()會修改字符集,因此如果select()調用是在一個循環中,則描述符集必須被重新賦值。

    1 /*以read操作為例*/
    2 while(1) {
    3    FD_ZERO(&readfds);
    4    FD_SET(fd, &readfds);
    5    select(nfds, &readfds, NULL, NULL, NULL);
    6 }

  5. 函數read()write()recv()send()以及select()可能會返回-1並且errno置位為EINTR,或這errno被賦值為EAGAIN(EWOULDBLOCK),這種情況需要被正確處理。如果程序中不接收任何信號,則不會得到EINTR。如果程序設為阻塞I/O,則不會收到EAGAIN。

    1 /*一般只需對EINTR進行處理就可以了,例子如下*/
    2 while(1) {
    3    ret = select(nfds, &readfds, NULL, NULL, NULL);
    4    if(ret == -1 && errno == EINTR)
    5        continue;
    6 }

  6. read()write()recv()send()返回0時建議關閉描述符並在字符集中移除此描述符(不關閉描述符並移除的話可能會導致未知錯誤,還是對此情況處理的好)。

定時器
在沒有usleep函數的系統中,可以應用select來實現,下例中實現了0.2秒的延時:

1 struct timeval tv;
2 tv.tv_sec = 0;
3 tv.tv_usec = 200000; /* 0.2 秒*/
4 select(0, NULL, NULL, NULL, &tv);

linux c中select使用技巧——計時器(轉)