linux下的select函數

該函數允許進程指示內核等待多個事件的任何一個發生,並且只在有一個或多個事件發生或經歷一段指定的時間後才能喚醒。


需要的庫

#include <sys/select.h>

#include <sys/time.h>


int select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptest, const, struct timeval *timeout);


fd_set是一組文件描述符的集合。

FD_CLR(inr fd,fd_set* set);用來清除描述詞組set中相關fd 的位
FD_ISSET(int fd,fd_set *set);用來測試描述詞組set中相關fd 的位是否爲真
FD_SET(int fd,fd_set*set);用來設置描述詞組set中相關fd的位
FD_ZERO(fd_set *set);用來清除描述詞組set的全部位

舉例:打開描述符1

fd_set rset;

FD_ZERO(&rset);

FD_SET(1,&rset);


中間的三個參數readset,writeset,exceptset指定我們要讓內核測試試着讀,寫和異常條件的描述符。


如果這三個參數都爲空,將獲取一個更爲精確的定時器。


timval結構

struct timeval{

long tv_sec;

long tv_usec;

}

參數可能

(1)永遠等待下去:僅有一個描述符準備好I/O時返回。

(2)等待固定時間:在不超過參數指向的timeval結構內的秒數和微妙數時,在有一個描述符準備好I/O是返回。

(3)根本不等待:檢查描述符後立即返回。

前兩種會被進程在等待期間捕獲的信號中斷,並從信號處理返回。


#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <string.h>

int main()
{
    int pipefd[2];
    int i;
    if (pipe(pipefd) < 0)//創建管道
    {
        printf("create pipe failed\n");
        return -1;
    }

    pid_t pid = fork();//創建進程
    if (pid == 0)//進入子進程
    {
        printf("child fork is running\n");
        close(pipefd[0]);//關閉管道讀取
        char str[50];
        for (i =0; i < 5; i++)
        {
            sprintf(str, "child fork msg %d ", i); 
            write (pipefd[1], str, strlen(str));//循環5次向管道輸入數據
            sleep(3);
        }
    }else
    {//父進程
        printf("parent fork is running\n");
        char str[50];
        close(pipefd[1]);//關閉管道輸入

        fd_set readset;
        for (i = 0; i < 5; i++ )
        {
            FD_ZERO(&readset);//因爲每次調用下面select語句後readset的值都會該改變,所以每次都要清空爲0.
            FD_SET(pipefd[0], &readset);//將pipefd[0]描述符添加到readset中
            FD_SET(0, &readset);//將(0)也就是標準輸入流的描述添加到readset中
            
            select(pipefd[0]+1, &readset, NULL, NULL, NULL);//對於第一個參數取readset中的最大描述符+1,此時堵塞等待標準輸入流,管道輸入流有數據輸入,其中一個有。立即返回

            if (FD_ISSET(pipefd[0], &readset))//判斷readset是否管道輸入
            {
                str[read(pipefd[0], str, 50)] = '\0';
                printf("parent recv is %s\n", str);
            }
            if (FD_ISSET(0, &readset))//判斷readset是否標準輸入流
            {
                str[read(0, str, 256)] = '\0';
                printf("stdout is %s\n", str);
            }
        }
        int status;
        wait(&status);
    }
    return 0;
}

結果,主要分爲兩種情況

情況一:不在終端輸入

parent recv is child fork msg 0 

parent recv is child fork msg 1 

parent recv is child fork msg 2

parent recv is child fork msg 3

parent recv is child fork msg 4 

情況一:在有終端輸入

parent recv is child fork msg 0 

輸入le

stdout is le 

parent recv is child fork msg 1 

輸入wang

stdout is lwang

parent recv is child fork msg 2

只出現3次管道輸出,原因是for循環5次,但在過程中有標準輸入流,每次有標準輸入流select馬上從堵塞中解除,消耗一次for循環。


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