低速系统调用 与 非阻塞I/O

本文探讨了两类低速系统调用:不带缓存I/O(如read、write)和打开某些类型文件(如FIFO)。介绍了如何通过设置O_NONBLOCK标志位实现非阻塞I/O,并详细讨论了其在不同场景下的工作原理。
低速系统调用是可能会使进程永远阻塞的一类系统调用

下面是两种低速调用


1. 不带缓存I/O:read,write

一个简单的例子:
一个进程从终端读取用户的输入,然后再从终端输出。如果用户离开了电脑前,那么系统就会一直等待用户输入,用户永远不回来,系统就永远阻塞(不考虑断电死机这些情况)

可以通过设置打开文件描述符的O_NONBLOCK标志位使得read,write成为非阻塞I/O
方法一:在使用open打开文件时,指定O_NONBLOCK标志
方法二:对于已经打开的文件描述符,使用fcntl函数打开其O_NONBLOCK标志位

设置了O_NONBLOCK标志位后,调用read,write函数不会发生阻塞,而是立即执行,如果没有读到相应的数据(或者写操作的目标不能立即接受数据),就立即返回出错。


因此,如果采用方法二对标准输入设置了O_NONBLOCK标志位,那么调用read函数从标准输入读用户输入,将立刻返回出错(用户输入的速度肯定赶不上函数调用的速度...)


再举一个例子:
先从一个大文件中读取数据存放在一个很大的char数组中,然后将char数组中写到标准输出。

如果标准输出被重定向到一个文件,那么只会调用write一次;

如果标准输出是终端,由于数据的规模超过了终端一次能接受的数据量,因此需要一个while循环,分多次写。那么分两种情况:
1)如果没有为标准输出设置O_NONBLOCK标志位,那么每次进程每次的write调用都是有效的;
2)如果为标准输出设置了O_NONBLOCK标志位,那么进程可能会发出多次write调用,而只有其中很少数的调用是有效的,大多数的write调用因为内核正忙(忙于处理之前write写到内核队列中的数据,也就是实际的I/O)等原因而无法处理,因为为标准输出设置了O_NONBLOCK标志位,所以不会阻塞等待内核接受调用,而是立即出错返回,进行下一次循环,直至内核接受调用。
这种方式成为"轮询",不会造成阻塞,但是在多用户系统上浪费了CPU时间(don't know why...)。



2. 打开某些类型的文件

比如(也是这类文件中我目前唯一了解的):FIFO

通常FIFO由两种进程打开:一种是为了读,另一种是为了写。
(通常不会有进程会用读写的方式打开一个FIFO文件,自读自写的话根本就不需要FIFO了)

如果某进程为读打开FIFO,且此时没有为写的进程打开该FIFO。如果没有设置O_NONBLOCK标志位,那么open函数会阻塞直至其他某个进程为写而打开该FIFO;类似地,只写open会阻塞到其他某个进程为读而打开该FIFO
注意,这个阻塞是可能使得系统永远阻塞的,因此打开一个FIFO是一个低速系统调用。

同样是上述情况,如果设置了O_NONBLOCK标志位,那么只读进程会立即返回,只写进程出错并返回-1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值