Linux下阻塞IO、非阻塞IO、同步IO、异步IO

一、进程间通信的同步/异步, 阻塞/非阻塞

进程间通信是通过send()和receive()两种基本操作完成的。消息传递可能是阻塞的或非阻塞的,也被称为同步异步的----《操作系统概念(第九版)》

可以总结为以下几种形式

  • 阻塞式发送:发送方send()后被阻塞,直到接收方接收
  • 非阻塞式发送:发送方send()后,立即可以其他操作
  • 阻塞式接收:接收方receive()后一直阻塞,直到消息到达
  • 非阻塞式接收:接收方receive()后,要么得到一个有效的结果,要么得到一个空值

也就是说,从进程间通信的角度来看,阻塞和同步(非阻塞和异步)是同义词,需要从发送方和接收方区分对待。

我们所说的“阻塞”是进程在发起一个系统调用后(recv),由于该系统调用不能立即完成,需要等待一段事件,于是内核将进程挂起为“等待”状态,以确保它不会被调度执行,占用CPU资源

二、IO系统调用的阻塞、非阻塞、同步、异步

阻塞和非阻塞描述的是进程的一个操作是否会使得进程转变为“等待”状态。

1.为什么会阻塞、非阻塞、同步、异步与IO关系起来呢?

  • 阻塞是和系统调用联系在一起的,要让一个进程进入“等待”状态,要么是它主动调用wait()或sleep()等挂起自己的操作,要么就是它调用系统调用,而系统调用涉及到IO操作,不能立即完成,于是内核先将该进程设置为“等待”状态,调度其他进程运行,等到IO操作完成,内核再让该进程回到“准备”状态。

2. 阻塞IO

  • 系统调用需要进程IO操作,但是此时数据还未准备好,导致进程进入“等待”状态,即阻塞
  • 举例:recv()函数
    #include <sys/types.h>
    #include <sys/socket.h>
    
    ssize_t recv(int sockfd, void *buf, size_t len, int flags);
    
    • 如果sockfd没有数据时,进程会等待数据到达,再继续。
    • 阻塞下,返回成功接收的数据长度,数据都写到buf中。
      在这里插入图片描述

3. 非阻塞IO

  • 系统调用需要进程IO操作,不管数据是否准备好,系统调用直接返回,继续执行程序。是一种非阻塞式行为。
  • 举例:recv()函数
     #include <sys/types.h>
    #include <sys/socket.h>
    
    ssize_t recv(int sockfd, void *buf, size_t len, int flags);
    
    • 设置sockfd是O_NONBLOCK
    • 返回-1,errno设置为EGAIN或EWOULDBLOCK。buf中可以是完成的结果,也可以是一个不完整的结果,还可以是一个空值。
      在这里插入图片描述
    • 上图最后一次read是阻塞的,因为他需要等待数据从内核态到用户态

4. 异步IO

  • POSIX规范,由操作系统完成IO操作,然后通知应用进程数据已经读写完成。

  • 系统调用需要进程IO操作,不管数据是否准备好,系统调用直接返回,继续执行程序;等IO操作完成后(这是由操作系统完成),内核会通知进程(一般是回调函数)。是一种非阻塞式行为。

  • Linux是没有完备的异步IO处理方式,但是可以模拟出这样的效果

  • 并发模式下的异步:程序执行依赖于事件驱动。

      • 举例:epoll_wait
           #include <sys/epoll.h>
           int epoll_wait(int epfd, struct epoll_event *events,
                          int maxevents, int timeout);
    
    • 在主线程中完成监听,子线程中进行读写处理。当主线程中epoll_wait阻塞时,就会执行子线程进行读写处理。
    • IO多路复用的监听和读写操作不在同一个线程下进行。

5. 同步IO

阻塞IO非阻塞IO都涉及到等待数据从内核态到用户态的过程,因此都是同步的

  • 并发模式下的同步
    • 举例:
      • mysql建立连接时,服务器发出连接请求,需要等到mysql返回响应,请求和响应是在同一个流程中。
      • redis的pipeline:服务器先把所有的连接请求发出去(在同一个包中),等待redis返回响应;redis统一处理所有连接请求,再返回。

6. 总结

  • 非阻塞I/O 系统调用 recv()操作立即返回的是任何可以立即拿到的数据,可以是完整的结果,也可以是不完整的结果,还可以是一个空值
  • 异步I/O系统调用recv()结果必须是完整的,但是这个操作完成的通知可以延迟到将来的一个时间点。
  • 同步IO系统调用 recv()后,没得到结果就不返回。
  • 阻塞IO系统调用 recv()后,没得到结果就不返回。
  • 非阻塞I/O 系统调用和异步I/O系统调用都是非阻塞式的,只是返回结果与处理IO的事件点不同。

参考文章:
https://www.zhihu.com/question/19732473/answer/241673170
https://zhuanlan.zhihu.com/p/368089289

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值