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循环。


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