I/O模式

用户空间&内核空间

32位操作系统的寻址空间为4G(2的32次方)。

操作系统的核心是内核,独立于普通的应用程序,可以访问受保护的内存空间,也有访问底层硬件设备的所有权限。为了保证用户进程不能直接操作内核(kernel),保证内核的安全,操心系统将虚拟空间划分为两部分,一部分为内核空间,一部分为用户空间。

针对linux操作系统而言,将最高的1G字节(从虚拟地址0xC0000000到0xFFFFFFFF),供内核使用,称为内核空间。

而将较低的3G字节(从虚拟地址0x00000000到0xBFFFFFFF),供各个进程使用,称为用户空间。

进程切换

实质就是OperationSystem内核挂起正在运行的进程A,然后将先前被挂起的另一个进程B恢复运行。

详情:http://www.cnblogs.com/wz19860913/archive/2010/05/25/1742583.html(后续会补充的即关于这里的见解)

进程阻塞

进程阻塞是运行着的进程自发产生的。所以只有处于运行态的进程(获得CPU),才可能将其转为阻塞状态

。进入阻塞状态的进程不占用cpu资源

文件描述符fd

文件描述符(file description) 是一个非负索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。

缓存I/O

大多数文件系统的默认 I/O 操作都是缓存 I/O。在 Linux 的缓存 I/O 机制中,操作系统会将 I/O 的数据缓存在文件系统的页缓存( page cache )中,也就是说,数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间。

---------------------------------------------------------------------

I/O模式

对于进程的一次I/O访问,kernel会有以下两个阶段

step 1:数据会拷贝到操作系统缓冲区(内核空间),即等待数据准备

step 2:数据从内核空间拷贝到进程空间

 

linux系统产生有以下几种I/O模式:

____1.阻塞I/O   (blocking I/O)

         

该模式中,在kernel的两个阶段中,进程是阻塞(不占用cpu资源)

____2.非阻塞I/O  (nonblocking I/O)

720333-20160916171226852-1916489268.png

该模式中,在kernel的两个阶段中,进程始终向kernel申请获取数据,所以进程是运行态的(始终占有cpu资源)

____3.I/O多路复用  (I/O multiplexing)

720333-20160916171333523-650292614.png

这就是我们所说的select ,poll,epoll

select 这个方法会不断的轮询用户的process所需的所有socket(I/O),当某个socket(I/O)数据获取到了,就返回给用户的process

注意当用户的process调用了select,那么整个进程都会被阻塞(block),而同时,kernel会“监视”所有select负责的socket,当任何一个socket中的数据准备好了,select就会返回。这个时候用户进程再调用read操作,将数据从kernel拷贝到用户进程,,,,,,,,,这样既用户的process可以处理多个socket(I/O)而又不在等待数据的过程中浪费cpu资源,适用于一个进程需要多个I/O的情况

在I/O multiplexing Model中,实际中,对于每一个socket,一般都设置成为non-blocking,但是,如上图所示,整个用户的process其实是一直被block的。只不过process是被select这个函数block,而不是被socket IO给block。

该模式中,通过一种机制一个进程能同时等待多个文件描述符,而这些文件描述符(套接字描述符)其中的任意一个进入读就绪状态,select()函数就可以返回。

_____4.信号驱动I/O   (signal driven I/O)

 

_____5.异步I/O   (asynchronous I/O)

 

720333-20160916171458461-2052304822.png

 

用户进程发起read操作之后,立刻就可以开始去做其它的事。而另一方面,从kernel的角度,当它受到一个asynchronous read之后,首先它会立刻返回,所以不会对用户进程产生任何block。然后,kernel会等待数据准备完成,然后将数据拷贝到用户内存,当这一切都完成之后,kernel会给用户进程发送一个signal,告诉它read操作完成了。

总结:

720333-20160916171648430-240094129.png

------------------------------------------------------------------------

I/O多路复用 select,poll,epoll

select,poll,epoll本质都是同步I/O,读写事件就绪后自己负责进行读写,也就是说这个读写过程是阻塞的

_____1.select

select(rlist, wlist, xlist, timeout=None)

select 函数监视的文件描述符分3类,分别是writefds、readfds、和exceptfds。调用后select函数会阻塞,直到有描述副就绪(有数据 可读、可写、或者有except),或者超时(timeout指定等待时间,如果立即返回设为null即可),函数返回。当select函数返回后,可以 通过遍历fdset,来找到就绪的描述符。

_____2.poll

int poll (struct pollfd *fds, unsigned int nfds, int timeout);

pollfd并没有最大数量限制(但是数量过大后性能也是会下降)。 和select函数一样,poll返回后,需要轮询pollfd来获取就绪的描述符。

_____2.epoll

1. int epoll_create(int size);
创建一个epoll的句柄,size用来告诉内核这个监听的数目一共有多大,这个参数不同于select()中的第一个参数,给出最大监听的fd+1的值,参数size并不是限制了epoll所能监听的描述符最大个数,只是对内核初始分配内部数据结构的一个建议
当创建好epoll句柄后,它就会占用一个fd值,在linux下如果查看/proc/进程id/fd/,是能够看到这个fd的,所以在使用完epoll后,必须调用close()关闭,否则可能导致fd被耗尽。

2. int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);
函数是对指定描述符fd执行op操作。
- epfd:是epoll_create()的返回值。
- op:表示op操作,用三个宏来表示:添加EPOLL_CTL_ADD,删除EPOLL_CTL_DEL,修改EPOLL_CTL_MOD。分别添加、删除和修改对fd的监听事件。
- fd:是需要监听的fd(文件描述符)
- epoll_event:是告诉内核需要监听什么事

3. int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
等待epfd上的io事件,最多返回maxevents个事件。
参数events用来从内核得到事件的集合,maxevents告之内核这个events有多大,这个maxevents的值不能大于创建epoll_create()时的size,参数timeout是超时时间(毫秒,0会立即返回,-1将不确定,也有说法说是永久阻塞)。该函数返回需要处理的事件数目,如返回0表示已超时。

 

 

参考:

http://www.cnblogs.com/alex3714/articles/5876749.html

 

 

转载于:https://my.oschina.net/u/3526387/blog/1541411

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值