操作系统之IO模型

2020-06-09  本文已影响0人  youzhihua

一、相关概念

1.1 同步与异步、阻塞与非阻塞

概念有些抽象,可以通过以下的例子来理解一下这组概念:

假设小明需要在网上下载一个软件:

1.2 用户态和内核态

1.2.1 用户态和内核态的基本概念

用户空间和内核空间

1.2.2 用户态切换到内核态的方式

1.3 文件描述符

内核(kernel)利用文件描述符(file descriptor)来访问文件。文件描述符是非负整数。打开现存文件或新建文件时,内核会返回一个文件描述符。读写文件也需要使用文件描述符来指定待读写的文件。

二、IO模型

2.1 同步阻塞IO

同步阻塞IO

2.2 同步非阻塞IO

同步非阻塞IO

2.3 IO多路复用

定义:单线程或单进程同时监测若干个文件描述符是否可以执行IO操作的能力,linux有三种实现方式,分别为select,poll和epoll。

IO多路复用

2.3.1 select


/* According to POSIX.1-2001, POSIX.1-2008 */
    #include <sys/select.h>
    /* According to earlier standards */
    #include <sys/time.h>
    #include <sys/types.h>
    #include <unistd.h>

    int select(int nfds, fd_set *readfds, fd_set *writefds,
                fd_set *exceptfds, struct timeval *timeout);

    int pselect(int nfds, fd_set *readfds, fd_set *writefds,
                fd_set *exceptfds, const struct timespec *timeout,
                const sigset_t *sigmask);

    void FD_CLR(int fd, fd_set *set);
    int  FD_ISSET(int fd, fd_set *set);
    void FD_SET(int fd, fd_set *set);
    void FD_ZERO(fd_set *set);

select的调用会阻塞到有文件描述符可以进行IO操作或被信号打断或者超时才会返回。

select将监听的文件描述符分为三组,每一组监听不同的需要进行的IO操作。readfds是需要进行读操作的文件描述符,writefds是需要进行写操作的文件描述符,exceptfds是需要进行异常事件处理的文件描述符。这三个参数可以用NULL来表示对应的事件不需要监听。

当select返回时,每组文件描述符会被select过滤,只留下可以进行对应IO操作的文件描述符。

FD_xx系列的函数是用来操作文件描述符组和文件描述符的关系。

FD_ZERO用来清空文件描述符组。每次调用select前都需要清空一次。

select可同时监听的文件描述符数量是通过FS_SETSIZE来限制的,在Linux系统中,该值为1024。

2.3.2 poll

#include <poll.h>

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

    #include <signal.h>
    #include <poll.h>

    int ppoll(struct pollfd *fds, nfds_t nfds,
            const struct timespec *tmo_p, const sigset_t *sigmask);

    struct pollfd {
        int fd; /* file descriptor */
        short events; /* requested events to watch */
        short revents; /* returned events witnessed */
    };

poll和select用三组文件描述符不同的是,poll只有一个pollfd数组,数组中的每个元素都表示一个需要监听IO操作事件的文件描述符。events参数是我们需要关心的事件,revents是所有内核监测到的事件。

poll在linux下没有监听的文件描述符数量限制,但是如果过多的话,速度也会变慢。

2.3.3 epoll

#include <sys/epoll.h>

    int epoll_create(int size);
    int epoll_create1(int flags);

    int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

    int epoll_wait(int epfd, struct epoll_event *events,
                int maxevents, int timeout);
    int epoll_pwait(int epfd, struct epoll_event *events,
                int maxevents, int timeout,
                const sigset_t *sigmask);

epoll_create用于创建一个epoll实例,而epoll_ctl用于往epoll实例中增删改要监测的文件描述符,epoll_wait则用于阻塞的等待可以执行IO操作的文件描述符直到超时。

epoll优于select&poll在下面几点:

2.4 异步IO

进程发起read操作之后,立刻就可以开始去做其它的事。而另一方面,从kernel的角度,当它受到一个asynchronous read之后,首先它会立刻返回,所以不会对用户进程产生任何block。然后,kernel会等待数据准备完成,然后将数据拷贝到用户内存,当这一切都完成之后,kernel会给用户进程发送一个signal,告诉它read操作完成了。  
这个模型工作机制是:告诉内核启动某个操作,并让内核在整个操作(包括第二阶段,即将数据从内核拷贝到进程缓冲区中)完成后通知我们。

异步IO模型
上一篇 下一篇

猜你喜欢

热点阅读