5种IO模型与阻塞IO

目录

5种IO模型

阻塞IO

非阻塞IO

信号驱动 IO

IO多路转接

异步 IO

高级 IO

同步通信 vs 异步通信

阻塞 vs 非阻塞

四者之间的关系

非阻塞 IO

fcntl

轮询读取标准输入


5种IO模型

阻塞IO

在内核将数据准备好之前,系统会一直等待,所有的套接字一般都默认是阻塞方式

非阻塞IO

如果内核还未将数据准备好,系统调用会直接返回,不过会将错误码设置为EWOULDBLOCK

非阻塞IO需要循环的方式反复读写文件描述符,对CPU是比较大的浪费

信号驱动 IO

内核将数据准备好时会发送信号,由对应的信号通知程序需要进行IO操作

IO多路转接

从流程上来看和阻塞IO差不多,但是最大的区别是阻塞IO一次等待一个文件描述符,而多路转接则是一次等待多个文件描述符

异步 IO
 

内核将数据拷贝完成时通知程序(也就是将IO处理完以后再告诉程序,信号是告诉程序什么时候可以处理IO)

任何IO的处理过程都分为等待与拷贝两部分,需要等待数据,数据到来才能拷贝

实际的场景中,等待所消耗的时间远远多于拷贝的时间,所以提高效率的办法就是尽量减少等待的时间

高级 IO

同步通信 vs 异步通信

这里的同步与异步与我们多线程时的同步不同,这里是通信的概念,关注的时消息通信机制

同步:一个调用在发出后一直等待,直到得到结果之后再返回

异步:一个调用在发出后直接返回,被调用方通过某种方式通知调用方结果已经处理完了

我们在多线程时提过同步与互斥,这主要解决的时访问共享资源的问题

进程/线程之间的同步时进程/线程之间的直接制约关系

为了完成任务而创建的多个进程/线程需要一定的工作次序,我们需要让他们按照某种次序去而等待,传递信息,尤其是访问共享资源的时候,我们为了实现同步而采用的方法为互斥,一个资源在同一时间最多只能被一个进程/线程访问到

阻塞 vs 非阻塞

阻塞和非阻塞关注的是程序在等待调用结果(消息, 返回值) 时的状态

1.阻塞调用是指调用结果返回之前, 当前线程会被挂起. 调用线程只有在得到结果之后才会返回

2.非阻塞调用指在不能立刻得到结果之前, 该调用不会阻塞当前线程

四者之间的关系

我们采取同步通信的方式,在调用结果出来之前一直等待,就是阻塞的方式,在阻塞期间程序没有办法接下来往后执行。

我们采用异步通信,使用的是非阻塞的方式,我们当前并不紧急需要该调用的结果,我们接下来执行其他方法即可,在调用结果处理完之后会通知程序,我们只需要在结果处理完之后直接拿到结果即可,这种方式就是非阻塞。

非阻塞 IO

我们此处主要讨论的是io多路转接

fcntl

该函数用于控制文件描述符

#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, ... /* arg */ );


//传入的cmd不同,后面的参数也不同
1.复制一个现有的描述符(cmd=F_DUPFD)
2.获得/设置文件描述符标记(cmd=F_GETFD 或 F_SETFD)
3.获得/设置文件状态标记(cmd=F_GETFL 或 F_SETFL)
4.获得/设置异步 I/O 所有权(cmd=F_GETOWN 或 F_SETOWN)
5.获得/设置记录锁(cmd=F_GETLK,F_SETLK 或 F_SETLKW)

我们此处主要使用第三种功能,也就是将文件描述符设置为非阻塞

void SetNonBlock(int fd)
{
    int f1=fcntl(fd,F_GETFL);
    if(f1<0)
    {
        perror("fcntl");
        return;
    }
    fcntl(fd,F_SETFL,f1|O_NONBLOCK);
}

这里取出来的文件状态标记也是一个位图,我们从文件描述符中取出来后为该标记增加上O_NONBLOCK(非阻塞标记)

轮询读取标准输入

void SetNonBlock(int fd)
{
    int f1=fcntl(fd,F_GETFL);
    if(f1<0)
    {
        perror("fcntl");
        return;
    }
    fcntl(fd,F_SETFL,f1|O_NONBLOCK);
}

int main()
{
    SetNonBlock(0);
    char buffer[1024];
    while(1)
    {
        int n=read(0,buffer,sizeof(buffer));
        if(n>0)
            printf("%s",buffer);
        else if(n<0)
        //read本身是阻塞的
        //当我们读取一个非阻塞的文件描述符,他就出错了直接返回-1
        {
            perror("read");
            sleep(1);
            continue;
        }
    }
}

上面的read主要是因为标准输入相当于程序启动时输入端始终打开,处于如果标准输入为阻塞文件描述符的话那就表现为阻塞状态,而非阻塞则表现为“暂时没数据”,因此返回的是-1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值