part6 高级IO

非阻塞IO

存在阻塞式的原因:

常见的阻塞:wait、pause、sleep等函数;read或write某些文件时

阻塞式的好处:提升OS整体性能

非阻塞

非阻塞的IO访问:O_NONBLOCK和fcntl

阻塞式IO的困境

程序中读取键盘

int main(void)
{
    char buf[100];
    //读取键盘,就是标准输入,stdin编号0
    memset(buf, 0, sizeof(buf));
    printf("before read.\n");
    read(0, buf, 2);
    printf("读出的内容是: [%s].\n", buf);
    return 0;
}

程序中读取鼠标

鼠标的设备文件在/dev/input/里面

int main(void)
{
    //读取鼠标
    int fd = -1;
    char buf[200];
    fd = open("/dev/input/mouse0", O_RDONLY);
    if(fd < 0)
    {
        perror("open");
        return -1;
    }
    memset(buf, 0, sizeof(buf));
    printf("before read.\n");
    read(fd, buf, 50);
    printf("读出的内容是: [%s].\n", buf);
    return 0;
}

程序中同时读取键盘和鼠标

问题:只能按照程序设定的方式先读键盘或者鼠标

并发式IO的解决方法

非阻塞式IO

程序中非阻塞式读取键盘

int main(void)
{
    char buf[100];
    int flag = -1;

    //将0号文件描述符变成非阻塞式的
    flag = fcntl(0, F_GETFL);//获取原来flag
    flag |= O_NONBLOCK; //添加非阻塞属性
    fcntl(0, F_SETFL, flag);//更新flag
    //0成为非阻塞式

    //读取键盘,就是标准输入,stdin编号0
    memset(buf, 0, sizeof(buf));
    printf("before read.\n");
    read(0, buf, 2);
    printf("读出的内容是: [%s].\n", buf);
    return 0;
}

程序中非阻塞式读取鼠标

int main(void)
{
    //读取鼠标
    int fd = -1;
    char buf[200];
    fd = open("/dev/input/mouse0", O_RDONLY | O_NONBLOCK);
    if(fd < 0)
    {
        perror("open");
        return -1;
    }
    memset(buf, 0, sizeof(buf));
    printf("before read.\n");
    read(fd, buf, 50);
    printf("读出的内容是: [%s].\n", buf);
    return 0;
}

程序中同时读取键盘和鼠标

int main(void)
{
    //读取鼠标
    int fd = -1;
    int flag = -1;
    char buf[200];
    int ret = 0;
    fd = open("/dev/input/mouse0", O_RDONLY | O_NONBLOCK);
    if(fd < 0)
    {
        perror("open");
        return -1;
    }
    //将0号文件描述符变成非阻塞式的
    flag = fcntl(0, F_GETFL);//获取原来flag
    flag |= O_NONBLOCK; //添加非阻塞属性
    fcntl(0, F_SETFL, flag);//更新flag
    //0成为非阻塞式
    while(1)
    {
        //读鼠标
        memset(buf, 0, sizeof(buf));
        //printf("before 鼠标 read.\n");
        ret = read(fd, buf, 50);
        if(ret > 0)
        {
            printf("鼠标读出的内容是: [%s].\n", buf);
        }

        //读键盘
        memset(buf, 0, sizeof(buf));
        //printf("before 键盘 read.\n");
        ret = read(0, buf, 2);
        if(ret > 0)
        {
            printf("键盘读出的内容是: [%s].\n", buf) ;
        }

    }

    return 0;
}
 

多路复用IO(IO multiplexing)

多路非阻塞式IO

selec函数t和poll函数(本身阻塞式)
int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);
nfds = 最大的文件描述符+1, fd_set表示文件描述符的集合

slect

int main(void)
{
    //读取鼠标
    int fd = -1,ret = 0;
    char buf[200];
    fd_set myset;
    struct timeval tm;
    fd = open("/dev/input/mouse0", O_RDONLY);
    if(fd < 0)
    {
        perror("open");
        return -1;
    }

    //当前有两个fd,一个是fd一个是0
    //处理myset
    FD_ZERO(&myset);
    FD_SET(fd, &myset);
    FD_SET(0, &myset);
    tm.tv_sec = 10;
    tm.tv_usec = 0;
    ret = select(fd+1, &myset, NULL, NULL, &tm);
    if(ret < 0)
    {
        perror("select:.\n");
        return -1;
    }else if(ret == 0)
    {
        printf("超时!");
    }else
    {
        //等到了一路IO,监测是哪个IO到了并处理
        if(FD_ISSET(0, &myset))
        {
            //处理键盘
            memset(buf, 0, sizeof(buf));
            read(0, buf, 2);
            printf("读出的内容是: [%s].\n", buf);

        }
        if(FD_ISSET(fd, &myset))
        {
            //处理鼠标
            memset(buf, 0, sizeof(buf));
            read(fd, buf, 50);
            printf("读出的内容是: [%s].\n", buf);

        }
    }

    return 0;
}

poll

int main(void)
{
    //读取鼠标
    int fd = -1,ret = 0;
    char buf[200];
    struct pollfd myfds[2]={0};
    fd = open("/dev/input/mouse0", O_RDONLY);
    if(fd < 0)
    {
        perror("open");
        return -1;
    }
    //初始化myfds数组
    myfds[0].fd = 0;            //键盘
    myfds[0].events = POLLIN;   //等待读操作
    myfds[1].fd = fd;           //鼠标
    myfds[1].events = POLLIN;    //等待读操作

    ret = poll(myfds, fd+1, 10000);
    if(ret < 0)
    {
        perror("poll:.\n");
        return -1;
    }else if(ret == 0)
    {
        printf("超时!");
    }else
    {
        //等到了一路IO,监测是哪个IO到了并处理
        for(int i = 0; i < 2; i++)
        {
            if(myfds[i].events == myfds[i].revents)
            {
                memset(buf, 0, sizeof(buf));
                read(0, buf, 2);
                printf("读出的内容是: [%s].\n", buf);
            }
        }
    }

    return 0;
}

外部阻塞式(本身阻塞式),内部非阻塞式自动轮询多路阻塞式IO

异步IO

异步IO就是OS用软件实现的一套中断响应系统

异步IO的工作方法:进程注册一个异步IO事件(使用signal注册一个信号SIGIO的处理函数),然后当前进程可以正常处理自己的事情,当异步事件发生后当前进程会收到SIGIO信号从而执行绑定的处理函数去处理异步事件

函数:
fcntl (F_GETFL、F_SETFL、O_ASYNC、F_SETOWN )
signal或者sigaction(SIGIO)

示例

int mousefd = -1;
//绑定SIGIO信号,处理异步通知事件
void func (int sig)
{
    char buf[200];
    if(sig != SIGIO)
    {
        return;
    }
    memset(buf, 0, sizeof(buf));
    read(mousefd, buf, 50);
    printf("鼠标读出的内容是: [%s].\n", buf);
}
int main(void)
{
    //读取鼠标
    int flag = -1;
    char buf[200];
    mousefd = open("/dev/input/mouse0", O_RDONLY);
    if(mousefd < 0)
    {
        perror("open");
        return -1;
    }
    //鼠标文件描述符设置为可以接收异步IO
    flag = fcntl(mousefd, F_GETFL);
    flag |= O_ASYNC;
    fcntl(mousefd, F_SETFL, flag);
    //把异步IO事件的接收进程设置为当前进程
    fcntl(mousefd, F_SETOWN, getpid());
    //注册当前进程的SIGIO捕获函数
    signal(SIGIO, func);

    //读键盘
    while(1)
    {
        memset(buf, 0, sizeof(buf));
        read(0, buf, 50);
        printf("键盘读出的内容是: [%s].\n", buf);
    }


    return 0;
}
 

存储映射IO

mmap函数(内存映射)

LCD显示和IPC之共享内存

特点:1、共享不是复制,减少内存操作。2、处理大文件时效率高,小文件性价比低

  • 12
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值