阻塞,非阻塞,同步,异步

先说说阻塞与非阻塞,这主要和程序等待消息时的状态有关

1、阻塞

程序会阻塞在某一个函数,而不往下执行,就如挂在那里一样,所有的其他业务也都不执行,为一直等到消息到来才往下执行。

2、非阻塞

程序不会阻塞在某一个函数,不等待消息到来,立即返回,往下执行。

举个例子,TCP协议中的send,系统会为其分配一块发送缓存区,假设现在总的缓存 区的大小为1000.,而缓存区里已经有了500个数据,这时调用send,发送1000个字节数据,这时如果在阻塞模式下,send的会先最多的数据放入缓存,直到缓存区满,然后程序就会阻塞在那里,一直等到将所有数据全部发出去为止,而如果在非阻塞模式下,send的会先将最多的数据放入缓存之后,就马上返回,剩余数据下回接着发送,不会卡在send函数中。

同步和异步这两个概念,其实是与消息通知机制有关的。

1、同步

发送消息,等待消息处理完后,才往下执行。就如MFC里的SendMessage(),

2、异步

发送消息,不等待消息处理完,就往下执行,让后通过特定的接口或者事件,消息通知你事情完成了。如MFC里的PostMessage()

粗略的讲了一下以上的两个概念,估计大家会问,那么阻塞与同步,非阻塞与异步有啥区别,用例说明。

比如我们现在去银行,你可以选择两种方式,取票等待和排队等待,如果你排队等待,你就得等前面所有人都办理完了,才能办理业务,此时如果在等待的过程中,你啥事都不能干,这时你就处于阻塞状态了,如果你还能一边打电话,一边喝饮料,看书,不过你还得时不时的抬头看看,前面的人还有多少,啥时候轮到你,免的错过办理,这时你就是处于同步状态。

也就是说,阻塞就是程序挂在那里,其他一切事情都不能做,直到当前事件返回为止,而同步得再原地等待消息,而与此同时,不影响其他业务的执行,体现在程序里就是其他线程的业务处理。

如果你取票等待,那么你只要坐在椅子上,这时你可以做你想做的事情,比如听听歌,看看书,打打电话,而到你时,窗口会自动叫号通知你,这时你就处于非阻塞状态。

如果此时你还觉得不过瘾,想出去溜达溜达,那么你可以和大厅的工作人员说一下,我去哪里,待会到我了,到某某地方通知我一下,然后你就可以出去做你想做的事情,直到工作人员来叫你为止。这时你就是处于异步状态。两者结合起来就是所谓的异步非阻塞模式,这种由于效率很高,在网络编程里经常被用到。

很多时候我们常常看到同步与异步,阻塞与非阻塞的出现。有的地方直接将同步与阻塞画上了等号。异步与非阻塞画上了等号。事实上这是不对的。同步不等于阻 塞,而异步也不等于非阻塞。下面就来仔细的看看同步与异步、阻塞与非阻塞的概念差别,及他们的组合应用。
同步:所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回。按照这个定义,其实绝大多数函数都是同步调用(例如sin, isdigit等)。但是一般而言,我们在说同步、异步的时候,特指那些需要其他部件协作或者需要一定时间完成的任务。最常见的例子就是 SendMessage。该函数发送一个消息给某个窗口,在对方处理完消息之前,这个函数不返回。当对方处理完毕以后,该函数才把消息处理函数所返回的LRESULT值返回给调用者
异步:异步的概念和同步相对。当一个异步过程调用发出后,调用者不能立刻得到结果。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者。以 CAsycSocket类为例(注意,CSocket从CAsyncSocket派生,但是起功能已经由异步转化为同步),当一个客户端通过调用 Connect函数发出一个连接请求后,调用者线程立刻可以朝下运行。当连接真正建立起来以后,socket底层会发送一个消息通知该对象。
这里 提到执行部件和调用者通过三种途径返回结果:状态、通知和回调。可以使用哪一种依赖于执行部件的实现,除非执行部件提供多种选择,否则不受调用者控制。如 果执行部件用状态来通知,那么调用者就需要每隔一定时间检查一次,效率就很低(有些初学多线程编程的人,总喜欢用一个循环去检查某个变量的值,这其实是一 种很严重的错误)。如果是使用通知的方式,效率则很高,因为执行部件几乎不需要做额外的操作。至于回调函数,其实和通知没太多区别
阻塞:阻塞调用是指调用结果返回之前,当前线程会被挂起。函数只有在 得到结果之后才会返回。
有人也许会把阻塞调用和同步调用等同起来,实际上他是不同的。对于同步调用来说,很多时候当前线程还是激活的,只是从逻辑上当前函数没有返回而已。例如,我们在 CSocket中调用Receive函数,如果缓冲区中没有数据,这个函数就会一直等待,直到有数据才返回。而此时,当前线程还会继续处理各种各样的消 息。如果主窗口和调用函数在同一个线程中,除非你在特殊的界面操作函数中调用,其实主界面还是应该可以刷新。
socket接收数据的另外一个函数 recv则是一个阻塞调用的例子。当socket工作在阻塞模式的时候,如果没有数据的情况下调用该函数,则当前线程就会被挂起,直到有数据为止。
非阻塞:非阻塞和阻塞的概念相对应,指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回。

上面这些概念都是教科书的概念,下面谈谈个人的理解。所谓同步就是当一个进程发起一个函数(任务)调用的时候,一直会到函数(任务)完成。进程继续往下执行。而异步这不会这样,异步情况下是当一个进程发 起一个函数(任务)调用的时候,不会等函数返回,而是继续往下执行当,函数返回的时候通过状态、通知、事件。等方式通知进程任务完成。

而阻塞和非阻塞的概念相对明了多了。阻塞是当请求不能满足的时候就试进程挂起,非阻塞则是直接返回。

它们的组合:(网络装载)

 2 给出了传统的阻塞 I/O 模型,这也是目前应用程序中最为常用的一种模型。其行为非常容易理解,其用法对于典型的应用程序来说都非常有效。在调用 read 系统调用时,应用程序会阻塞并对内核进行上下文切换。然后会触发读操作,当响应返回时(从我们正 在从中读取的设备中返回),数据就被移动到用户空间的缓冲区中。然后应用程序就会解除阻塞(read 调用返 回)。

 2. 同步阻塞 I/O 模型的典型流程

从应用程序的角度来说,read 调用会延续很长时间。实际上,在内核执行读操作和其他工作时,应用程序的确会被阻塞。

PS. 我理解这里的意思是,read请求是阻塞的,也没有异步通知机制,因为应用程序一直在这个过程中等待,即一直在主动查询,所以是同步的。(顺序)

同步非阻塞 I/O

同步阻塞 I/O 的一种效率稍低的变种是同步非阻塞 I/O。在这种模型中,设备是以非阻塞的形式打开的。这意味着 I/O 操作不会立即完成,read 操作可能会返回一个错误代码,说明这个命令不能立即满足(EAGAIN 或EWOULDBLOCK),如图 3 所示。

 3. 同步非阻塞 I/O 模型的典型流程

 

非阻塞的实现是 I/O 命令可能并不会立即满足,需要应用程序调用许多次来等待操作完成。这可能效率不高,因为在很多情况下,当内核执行这个命令时,应用程序必须要进行忙 碌等待,直到数据可用为止,或者试图执行其他工作。正如图 3 所示的一样,这个方法可以引入 I/O 操作的延时,因为数据在内核中变为可用到用户调用 read 返回数据之间存在一定的间隔,这会导致整体数据吞吐量的降低。

PS. 我理解这里的意思是,read请求是非阻塞的,但是这里没有异步通知机制,而需要应用程序主动查询,所以是同步的。(多次试探)

异步阻塞 I/O

另外一个阻塞解决方案是带有阻塞通知的非阻塞 I/O。在这种模型中,配置的是非阻塞 I/O,然后使用阻塞 select 系统调用来确定一个 I/O 描述符何时有操作。使 select 调用非常有趣的是它可以用来为多个描述符提供通知,而不仅仅为一个描述符提供通知。对于每个提示符来说,我们可以请求这个描述符可以写数据、有读数据可用 以及是否发生错误的通知。

 4. 异步阻塞 I/O 模型的典型流程 (select)

 

select 调用的主要问题是它的效率不是非常高。尽管这是异步通知使用的一种方便模型,但是对于高性能的 I/O 操作来说不建议使用。

PS. 我理解这里的意思是,read请求实际上是非阻塞的,但是在异步通知方式上,采用了阻塞的slect系统调用,导致应用程序被阻塞,所以虽然异步,但任然阻 塞。(等待通知,自己完成)

异步非阻塞 I/O(AIO)

最后,异步非阻塞 I/O 模型是一种处理与 I/O 重叠进行的模型。读请求会立即返回,说明 read 请求已经成功发起了。在后台完成读 操作时,应用程序然后会执行其他处理操作。当 read 的响应到达时,就会产生一个信号或执 行一个基于线程的回调函数来完成这次 I/O 处理过程。

 5. 异步非阻塞 I/O 模型的典型流程

 

在一个进程中为了执行多个 I/O 请求而对计算操作和 I/O 处理进行重叠处理的能力利用了处理速度与 I/O 速度之间的差异。当一个或多个 I/O 请求挂起时,CPU 可以执行其他任务;或者更为常见的是,在发起其他 I/O的同时对已经完成的 I/O 进行操作。

PS. 我理解这里的意思是,read请求实际上是非阻塞的,但是在异步通知方式上,采用了回调函数,无需应用程序再去处理。(委托完成)

异步 I/O 的动机

从前面 I/O 模型的分类中,我们可以看出 AIO 的动机。阻塞模型要求在 I/O 操作开始时阻塞应用程序,这意味着不可能同时重叠进行处理和 I/O 操作。同步非阻塞模型允许处理和 I/O 操作重叠进行,但是这需要应用程序根据重现的规则来检查 I/O 操作的状态。这样就剩下异步非阻塞 I/O 了,它允许处理和 I/O 操作重叠进行,包括 I/O 操作完成的通知。

这里我要特别强调一下异步IO和非阻塞IO的区别,异步IO就是把IO提交给系统,让系统替你做,做完了再 用某种方式通知你;非阻塞IO就是你要通过某种方式不定时地向系统询问你是否可以开始做某个IO,当可以开始后,还是要自己来完成IO

原文地址:https://www.cnblogs.com/muzinan110/p/4992313.html