linux的同步,异步,阻塞,非阻塞

来源:互联网 发布:门禁一卡通软件设置 编辑:程序博客网 时间:2024/06/04 17:42

linux中关于IO操作有同步,异步,阻塞,非阻塞几种模式,这几种模式可能有些同学会有点迷糊,把同步和阻塞混为一起,把异步和非阻塞混一起.其实这四种模式的关系是:阻塞和非阻塞都属于同步.

1. 基础知识
    我们都知道linux将所有的设备都看作文件,那么我们对linux的设备操作都可以看做是文件操作.我们打开一个文件的时候内核会返回给我们一个文件描述符,那么我们对文件的操作都是文件描述符来操作的.
    系统调用是如何完成IO操作的呢?网上有一个系列文章讲解一次IO操作的真实过程<一个IO的传奇一生>.
    linux将内存分为内核区,用户区; linux内核给我们管理所有的硬件资源,应用程序通过调用系统调用和内核交互,达到使用硬件资源的目的; 应用程序通过系统调用read发起一个读操作;这时候内核创建一个文件描述符,并通过驱动程序向硬件发送读指令,并将读的的数据放在这个描述符对应结构体的缓存区。但这个结构体是在内核内存区的。需要将这个数据读到用户区。这样完成了一次读操作;
    但是大家都知道I/O设备相比cpu的速度是极慢的。linux提供的read系统调用,也是一个阻塞函数。这样我们的应用进程在发起read系统调用时,就必须阻塞,就进程被挂起而等待文件描述符的读就绪;
    这里,我们先了解一下,什么是文件描述符读就绪,什么是写就绪?
    读就绪:就是这个文件描述符的接收缓冲区中的数据字节数大于等于套接字接收缓冲区低水位标记的当前大小;
    写就绪:该描述符发送缓冲区的可用空间字节数大于等于描述符发送缓冲区低水位标记的当前大小.
    接收低水位标记和发送低水位标记:由应用程序指定,比如应用程序指定接收低水位为64个字节。那么接收缓冲区有64个字节,才算fd读就绪
2. 各种IO模式比较
   从上面我们知道一个IO操作包含了基本的两步:描述符就绪,内核数据到用户数据的拷贝.一次IO操作可能需要花费几秒钟甚至更长的时间.
   阻塞:如果文件描述符还没就绪那么就一直等待,直到描述符就绪ok.等到描述符就绪ok以后就开始其他的IO步骤,最后完成IO操作以后返回.
   非阻塞:如果文件描述符还没就绪那么就直接返回并返回一个错误码,不再傻等到描述符就绪.
   阻塞和非阻塞的区别就是:如果此时因为各种原因不能马上进行IO操作那么如果继续等待则是阻塞IO,否则为非阻塞IO.
   同步:请求阻塞,等待一次IO操作全部完成再返回.这里的一次IO操作包含了上面的阻塞和非阻塞模式,也就是这次IO操作可能成功也有可能会失败,但是一定要等待IO操作全部完成再返回.
   异步:请求不阻塞,不等待IO操作完成再返回.等到IO操作完成以后内核会通知我们IO操作已经完成.
   同步和异步的区别就是:等待一次IO操作完成再返回则是同步,否则为异步.
   我们知道信号是一种异步通知的方式,那么IO操作加上信号操作是不是就可以变成异步IO?
   异步非阻塞(信号驱动式IO):内核在描述符就绪时发送SIGIO信号通知进程,进程通过信号处理函数接收数据.这就是上面提到的加上异步的信号就瞬时变成了高大上的异步IO了,但是这种方式和真正的异步IO还是有一些区别的,异步IO(AIO)是等IO操作完成以后发送通知(不是通过信号的方式),但是信号驱动的异步IO是等描述符就绪发送通知,而不是等IO操作全部完成,我们需要在信号处理函数中再去同步的读取数据(只是此时我们不会因为描述符还没准备好而阻塞了).
   异步非阻塞(IO复用):linux提供了select,poll,进程可以将一个或多个fd传递给select.select系统调用会阻塞直到其中的某一个fd就绪,此时我们再调用read等操作就不会因为描述符未就绪而阻塞,但是其实跟上面的信号驱动IO也是一样的.所以我个人认为应该把这种模式改成异步阻塞IO.

0 0
原创粉丝点击