C言語システムコール-select

selectシステムコール

概要

selectは複数のファイルディスクリプタ(ファイル記述子)を監視/制御します。


ファイルディスクリプタで処理を待ち合わせるシステムコール(readやacceptなど)を実行すると、データが到着するなどの一連の処理が完了するまでシステムコールから処理制御はリターンされません。

つまり、ファイルディスクリプタへのデータ到着を待ち合わせる場合、待ち合わせ状態のディスクリプタにデータが到着して処理が完了するまでは、他のディスクリプタに到着したデータは処理を見合わせることとなります。

そのような場合にselectシステムコールを利用することで、複数のファイルディスクリプタに対する状態変化を監視して、効率的な待ち合わせ制御を行うことが可能になります。


selectでは、timeout引数を指定することで待ち合わせ処理における時間切れを指定することができるため、処理タイマーとして利用することもできます。


サンプルプログラム

標準入力を数秒待ち合わせるselectです。


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/types.h>

/*!
 * @brief  標準入力から標準出力へエコーする
 */
static int
echo_process(void)
{
    ssize_t rnum = 0;
    ssize_t wnum = 0;
    char buf[BUFSIZ] = {"¥0"};

    rnum = read(0, buf, sizeof(buf));
    if(rnum < 0){
        printf("Error: read(%d) %s\n", errno, strerror(errno));
        return(-1);
    }

    wnum = write(1, buf, rnum);
    if(wnum < 0){
        printf("Error: write(%d) %s\n", errno, strerror(errno));
        return(-1);
    }

    return(0);
}

/*!
 * @brief     標準入力を待ち合わせる。
 * @param[in] filepath  ファイルパス名
 * @return    0:success/-1:failure
 */
static int
select_stdin(void)
{
    int rc = 0;
    struct timeval tv = {0};
    fd_set fds;

    FD_ZERO(&fds);   /* 初期化 */
    FD_SET(0, &fds); /* ディスクリプタを設定 */
 
    /* 待ち合わせ時間 : 3.5秒 */
    tv.tv_sec  = 3;
    tv.tv_usec = 500000;

    rc = select(1, &fds, NULL, NULL, &tv);
    if(rc < 0){
        printf("Error: select() %s\n", strerror(errno));
        return(-1);
    }

    if(rc == 0){
        /* タイムアウト */
        printf("CAUTION: timeout\n");
        return(-1);
    }

    if(FD_ISSET(0, &fds)){
        /* 待ち合わせに到着 */
        echo_process();
    }

    return(0);
}

int
main(int argc, char *argv[])
{
    int rc = 0;

    if(argc != 1){
        fprintf(stderr, "Usage: %s\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    rc = select_stdin();
    if(rc != 0) exit(EXIT_FAILURE);

    exit(EXIT_SUCCESS);
}


関連ページ