*nix I/O model

一般来说,*nix支持四种I/O结构,分别是阻塞式I/O、非阻塞式I/O、I/O复用,信号驱动I/O。

下面分别介绍一下这四种I/O结构:

一,阻塞式I/O。

这是*nix中使用最多的I/O模式,默认情况下对于设备节点的read,对于套接字的read/recvfrom都是阻塞的。

进程(线程)进入这个系统调用,一般来说在申请的条件(如read到足够的数据)被满足之前task是阻塞的,直到条件满足或者被信号中断才回返回。

一般来说,这种导致task挂起的方式浪费cpu,是不太合理的。

但是合理使用时,也能带来好处,比如说,这是一个天然的同步机制啊,不见兔子不撒鹰;

同时,搭配ioctl的某些cmd命令(当然,需要fd在驱动中支持相关cmd,如:FIONREAD)在提前获取到驱动(内核)buf信息时,在给内核指定读取长度,这样就不会造成阻塞。


二,非阻塞式I/O

一个fd的I/O是否阻塞是可以通过系统调用设置的,*nix中一般是ioctl,cmd为FIONBIO(在嵌入式设备中,对于串口之类的节点,为了提高效率,一般自己实现的驱动里就直接将fd配成非阻塞式,无需通过ioctl设置),设置为非阻塞式I/O时,如果申请条件得不到满足一般会返回一些错误信息,错误返回之后继续申请,再返回再申请,直到得到合理响应后返回成功,这就是所谓的轮训。

阻塞式I/O和非阻塞式I/O的区别,很想互斥锁和自旋锁的区别,一个是拿不到资源就在挂起直到资源继续执行,一个拿不到资源就一直尝试去拿。一个哥们说,他们像是一个30岁的男人和20岁的毛头小伙在追求姑娘,没有哪个好或者不好,关键在于你追求的对象和你们所在的环境,当然还有你的‘颜值’和车房,扯远了。


三,信号驱动式I/O

怎么理解?就是该干嘛干嘛去,等电话响了(就是信号SIGIO)就回家吃饭(妈,我想你了)。

怎么样对一个fd启动信号驱动式I/O呢?

在*nix中需要以下三个步骤:

1,信号驱动,所以必须先建立一个信号处理函数,就是先跟妈妈商量好,电话打来就回家吃饭。

2,设置fd的属主,通过fcntl的F_SETOWN命令设置。如果是ioctl就是FIOSETOWN命令咯

      ----fcntl(fd,F_SETOWN,getipd());

3,通过fcntl的F_SETFL命令打开O_ASYNC标志来开启该fd的信号驱动式I/O。如果是ioctl就是FIOASYNC命令咯。

      ----ioctl(fd,FIOASYNC,&flag)

在执行完以上三个步骤之后,进入系统调用后立即返回,task继续运行,并不阻塞也不轮询。当申请条件满足时,kernel会为该task产生一个SIGIO信号,收到该信号时,第一步的信号处理函数就可以执行相关I/O动作了。

这个模式在某种程度上来说属于并发了,如果把信号的产生和接受也当做一个任务的话,效率要高一些。


四,I/O复用

通过类似select或者poll的syscall,阻塞在syscall中,而不是阻塞在真正的I/O系统调用上。

select/poll返回后,fd即可读或可写,可以继续执行I/O动作。

实际上,如果不是这两个系统调用能一次处理多个fd,鉴于多了一个系统调用,反而是一种效率下降。

尽管这是使用最多的一种I/O线程处理方式,但是select的实现机制并不完美,遭到了很多批评,于是有了pselect,同时,poll做了改善,同样不尽如人意,这两个函数内容很多,可以单独写一篇blog了,不在这里扩散。


其实据《UNIX Network Programming》介绍,POSIX还规范了一种叫做异步I/O的I/O模型,跟信号驱动类似,不同的是信号驱动I/O是由内核通知我们何时可以启动一个I/O操作;异步I/O是kernel通知我们I/O操作何时完成。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值