Linux select()

Koma_Wong發表於2018-10-13

先看看linux的man select手冊(節選):

$man select
SELECT(2)                      Linux Programmer's Manual                      SELECT(2)



NAME
       select,  pselect, FD_CLR, FD_ISSET, FD_SET, FD_ZERO - synchronous I/O multiplex‐
       ing

SYNOPSIS
       /* According to POSIX.1-2001 */
       #include <sys/select.h>

       /* According to earlier standards */
       #include <sys/time.h>
       #include <sys/types.h>
       #include <unistd.h>

       int select(int nfds, fd_set *readfds, fd_set *writefds,
                  fd_set *exceptfds, struct timeval *timeout);

       void FD_CLR(int fd, fd_set *set);
       int  FD_ISSET(int fd, fd_set *set);
       void FD_SET(int fd, fd_set *set);
       void FD_ZERO(fd_set *set);

       #include <sys/select.h>

       int pselect(int nfds, fd_set *readfds, fd_set *writefds,
                   fd_set *exceptfds, const struct timespec *timeout,
                   const sigset_t *sigmask);

RETURN VALUE
       On  success,  select()  and pselect() return the number of file descriptors con‐
       tained in the three returned descriptor sets (that is, the total number of  bits
       that  are  set in readfds, writefds, exceptfds) which may be zero if the timeout
       expires before anything interesting happens.  On  error,  -1  is  returned,  and
       errno  is  set  appropriately;  the sets and timeout become undefined, so do not
       rely on their contents after an error.

下面就我的理解簡單介紹:

將檔案描述符用FD_SET巨集新增到一個長整型long的fd_set中,然後select會檢測核心對哪個檔案描述符新增到fd_set中的檔案描述符感興趣。

下面將man select中的例子做出完整的註釋說明,並作出少許改動:

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>

#define debug() printf("\033[31m%s\033[m:%d\n", __func__, __LINE__)

int
main(void)
{
    fd_set rfds;         /*建立一個fd_set型別資料,實則為long,使用其中的位*/
    struct timeval tv;   /*宣告一個時間變數,裡面包括秒和毫秒兩個欄位*/
    int retval;          /*返回值*/

    /* Watch stdin (fd 0) to see when it has input. */
    FD_ZERO(&rfds);      /*將fd_set置零*/
    FD_SET(0, &rfds);    /*將stdin加入到這個rfds中,其等同於下面的註釋行,即fileno(stdin)=0*/
    //FD_SET(fileno(stdin), &rfds);
    
    /* Wait up to two seconds. */
    tv.tv_sec = 2;      /*設定時間為2s,兩秒內stdin無操作則select不再阻塞,繼續執行*/
    tv.tv_usec = 0;

    retval = select(1, &rfds, NULL, NULL, &tv); /*呼叫select函式*/
    /* Don't rely on the value of tv now! */

    if (retval == -1)   /*如果select出錯*/
    {
        debug();
        perror("select()");
    }
    else if (retval)    /*如果stdin有輸入*/
    {
        debug();
        printf("Data is available now.\n");
        /* FD_ISSET(0, &rfds) will be true. */
    }
    else                /*否則*/
    {
        debug();
        printf("No data within five seconds.\n");
    }
    exit(EXIT_SUCCESS);
}

執行結果:

$ gcc select.c 
[Toa@toa ~]$ ./a.out 
main:41
No data within five seconds.
$ ./a.out 
123
main:35
Data is available now.

 

相關文章