linux 中阻塞与非阻塞 同步与异步

 

简单点说: 阻塞就是干不完不准回来, 非阻塞就是你先干,我先看看有其他事没有,完了告诉我一声。

我们拿最常用的send和recv两个函数来说吧。比如你调用send函数发送一定的Byte,在系统内部send做的工作其实只是把数据传输(Copy)到TCP/IP协议栈的输出缓冲区,它执行成功并不代表数据已经成功的发送出去了,如TCP/IP协议栈没有足够的可用缓冲区来保存你Copy过来的数据的话,这时候就体现出阻塞和非阻塞的不同之处了:对于阻塞模式的socket,send函数将不返回,直到系统缓冲区有足够的空间把你要发送的数据Copy过去以后才返回。而对于非阻塞的socket来说,send会立即返回,WSAEWOULDDBLOCK告诉调用者说:"发送操作被阻塞了!!!你想办法处理吧。" 对于recv函数,同样道理,该函数的内部工作机制其实是在等待TCP/IP协议栈的接收缓冲区通知它说:“嗨,你的数据来了。”对于阻塞模式的socket来说,如果TCP/IP协议栈的接收缓冲区没有通知一个结果给它,它就一直不返回,耗费着系统资源。对于非阻塞模式的socket,该函数会马上返回,然后告诉你:WSAEWOULDDBLOCK—"现在没有数据,回头再来看看" 。

在进行网络编程时,我们常常见到同步、异步、阻塞和非阻塞四种调用方式。这些方式彼此概念并不好理解。下面是我对这些术语的理解。同步、异步指的是通信模式,而阻塞和非阻塞指的是在接收和发送时是否等待动作完成才返回,所以不能混淆这四个词。通信的同步,主要是指客户端在发送请求后,必须得在服务端有回应后才发送下一个请求。所以这个时候的所有请求将会在服务端得到同步;其次是通信的异步,指客户端在发送请求后,不必等待服务端的回应就可以发送下一个请求,这样对于所有的请求动作来说将会在服务端得到异步,这条请求的链路就象是一个请求队列,所有的动作在这里不会得到同步的。阻塞和非阻塞只是应用在请求的读取和发送。在实现过程中,如果服务端是异步的话,客户端也是异步的话,通信效率会很高,但如果服务端在请求的返回时也是返回给请求的链路时,客户端是可以同步的,这种情况下,服务端是兼容同步和异步的。相反,如果客户端是异步而服务端是同步的也不会有问题,只是处理效率低了些。
在说到同步和异步的区别之前我先举一个简单的例子:

同步.一条马路,只能开一辆车,等这个车开走了,才能开另一辆.
异步.一条马路,随便开多少车.
同步:所谓同步,就是在发出一个功能调用时,在没有得到结果之前,该调用就不返回。按照这个定义,其实绝大多数函数都是同步调用(例如sin, isdigit等)。但是一般而言,我们在说同步、异步的时候,特指那些需要其他部件协作或者需要一定时间完成的任务。最常见的例子就是 SendMessage。该函数发送一个消息给某个窗口,在对方处理完消息之前,这个函数不返回。当对方处理完毕以后,该函数才把消息处理函数所返回的 LRESULT值返回给调用者。

异步:异步的概念和同步相对。当一个异步过程调用发出后,调用者不能立刻得到结果。实际处理这个调用的部件在完成后,通过状态、通知和回调来通知调用者。以CAsycSocket类为例(注意,CSocket从CAsyncSocket派生,但是其功能已经由异步转化为同步),当一个客户端通过调用 Connect函数发出一个连接请求后,调用者线程立刻可以朝下运行。当连接真正建立起来以后,socket底层会发送一个消息通知该对象。这里提到执行部件和调用者通过三种途径返回结果:状态、通知和回调。可以使用哪一种依赖于执行部件的实现,除非执行部件提供多种选择,否则不受调用者控制。如果执行部件用状态来通知,那么调用者就需要每隔一定时间检查一次,效率就很低(有些初学多线程编程的人,总喜欢用一个循环去检查某个变量的值,这其实是一种很严重的错误)。如果是使用通知的方式,效率则很高,因为执行部件几乎不需要做额外的操作。至于回调函数,其实和通知没太多区别。

阻塞:阻塞调用是指调用结果返回之前,当前线程会被挂起。函数只有在得到结果之后才会返回。有人也许会把阻塞调用和同步调用等同起来,实际上他是不同的。对于同步调用来说,很多时候当前线程还是激活的,只是从逻辑上当前函数没有返回而已。例如,我们在CSocket中调用Receive函数,如果缓冲区中没有数 据,这个函数就会一直等待,直到有数据才返回。而此时,当前线程还会继续处理各种各样的消息。如果主窗口和调用函数在同一个线程中,除非你在特殊的界面操函数中调用,其实主界面还是应该可以刷新。socket接收数据的另外一个函数recv则是一个阻塞调用的例子。当socket工作在阻塞模式的时候,如果没有数据的情况下调用该函数,则当前线程就会被挂起,直到有数据为止。

非阻塞:非阻塞和阻塞的概念相对应,指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回。对象的阻塞模式和阻塞函数调用对象是否处于阻塞模式和函数是不是阻塞调用有很强的相关性,但是并不是一一对应的。阻塞对象上可以有非阻塞的调用方式,我们可以通过一定的API去轮询状态,在适当的时候调用阻塞函数,就可以避免阻塞。而对于非阻塞对象,调用特殊的函数也可以进入阻塞调用。函数select就是这样的一个例子。阻塞通信通过重叠通信和计算在许多系统能提高性能。由一个智能通信控制器自动地执行通信的系统是真实的。轻-重线索是取得这种重叠的一种机制。导致好性能的一个可选的机制是使用非阻塞通信。一个阻塞发送开始调用初始化这个发送操作,但不完成它。在这个消息被从这个发送缓存拷出以前,这个发送开始调用将返回。需要一个独立的“发送完成”调用完成这个通信,例如,检验从发送缓存拷出的数据。用适当的硬件,在发送被初始化后和它完成以前,来自发送者存储的数据转换 可以和在发送者完成的计算同时进行。类似地,一个非阻塞“接收开始调用”初始化这个接收操作, 但不完成它。在一个消息被存入这个接收缓存以前,这个调用将返回。须要一个独立的“接收完成”调用完成这个接收操作,并检验被接收到这个接收缓存的数据。用适当的硬件,在接收操作初始化后和它完成以前,到接收者存储的数据转换可以和计算同时进行。非阻塞接收的使用虽着信息较早地在接收缓存位置被提供,也可以避免系统缓存和存储器到存储器拷贝。 非阻塞发送开始调用能使用与阻塞发送一样的四种模式: 标准, 缓存, 同步和准备好模式。这些具有同样的意义。无论一个匹配接收是否已登入,能开始除“准备好”以外的所有模式的发送;只要一个匹配接收已登入,就能开始一个非阻塞“准备好”发送。在所有情况下,发送开始调用是局部的:无论其它进程的状态如何,它立刻返回。如果这个调用使得一些系统资源用完,那么它将失败并返回 一个错误代码。高质量的MPI实现应保证这种情况只在“病态”时发生。即,一个MPI实现将能支持大数量挂起非阻塞操作。当数据已被从发送缓存拷出时,这个发送完成调用返回。它可以带有附加的意义,这取决于发送模式。如果发送模式是“同步的”,那么只有一个匹配接收已开始这个发送才能完成。即,一个接收已被登入,并已和这个发送匹配。这时,这个发送完成调用是非局部的。注意,在接收完成调用发生以前,如果一个同步、非阻塞发送和一个非阻塞接收匹配, 它可以完成。(发送者一“知道”转换将结束,它就能完成,但在接收者“知道”转换将结束以前)。如果发送模式是“缓存”,并没有挂起接收,那么消息必须被缓存。这时,发送完成调用是局部的,而且无论一个匹配接收的状态如何,它必须成功。如果发送模式是标准的,同时这个消息被缓存,那么在一个匹配接收发生以前,发送结束调用可以返回。另一方面,发送完成直到一个匹配接收发生才可以完成,并且这个消息已被拷到接收缓存。非阻塞发送能被用阻塞接收匹配,反过来也可以。给用户的建议. 一个发送操作的完成, 对于标准模式可以被延迟, 对于同部模式必须延迟, 直到一个匹配接收登入。这两种情况下非阻塞发送的使用允许发送者提前于接收者进行,以便在两进程的速度方面,计算更容忍波动。缓存和准备好模式中的非阻塞发送有一个更有限的影响。一可能一个非阻塞发送将返回,而一个阻塞发送将在数据被从发送者存储拷出后返回。只要在数据拷贝能和计算同时的情况下,非阻塞发送的使用有优点。消息发送模式隐含着由发送者初始化通信。当发送者初始化通信(数据被直接移到接收缓存, 并不要求排队一个挂起发送请求) 时,如果一个接收已登入,这个通信一般将有较低的额外负担。但是,只在匹配发送已发生后,一个接收操作能完成。当非阻塞接收等待发送时,没有阻塞接收,它的使用允许得到较低的通信额外负担。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/444990.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

leecode62 不同路径

示例 1: 输入: m 3, n 2 输出: 3 解释: 从左上角开始,总共有 3 条路径可以到达右下角。 1. 向右 -> 向右 -> 向下 2. 向右 -> 向下 -> 向右 3. 向下 -> 向右 -> 向右 示例 2: 输入: m 7, n 3 输出: 28 思路:太过于简单&#xf…

数据库的查询优化建议整理

从大多数数据库应用系统的实例来看,查询操作在各种数据库操作中所占据的比重最大,而查询操作所基于的SELECT语句在SQL语句中又是代价最大的语句。 查询语句(SELECT)的优化建议 (1)、合理使用索引:where子句中变量顺序应与索引字键顺序相同。 如:create index test_idx…

Github(4)-远程操作

使用github 托管代码简单使用教程--远程操作3.连接本地仓库与远程仓库3.1 git clone 克隆实现链接3.2 git remote add origin4.远程操作4.1 git checkout -b 切换分支14.2 git branch 查看分支4.3 git merge 合并分支4.3.1 step1:切换成主分支4.3.2 step2&#xff1…

leetcode64 最小路径和

给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。 说明:每次只能向下或者向右移动一步。 示例: 输入: [ [1,3,1], [1,5,1], [4,2,1] ] 输出: 7 解释: 因为路径 1→3→1→1→1 的总…

online游戏服务器架构--网络架构

启动:父进程启动;子进程启动;网络架构。 每个父进程携带N个子进程,子进程负责处理业务逻辑和其它数据,而父进程只是将客户端的请求路由到各个子进程,路由的策略非常简单,父进程将请求包按照轮流…

online游戏服务器架构—用户登录数据组织 .

sprite_t类型的数据结构是核心数据结构,每一个登录用户对应一个,它的初始化在用户登录的时候,此后一直到用户退出或者离线一直保存在系统内存当中,在此过程中该sprite_t数据结构被保存在两个哈希表当中,一个是以用户的…

leetcode300 最长上升子序列

经典题&#xff0c;不解释&#xff0c;可以看我之前文章。 普通dp public class Solution {public int lengthOfLIS(int[] nums) {if (nums.length 0) {return 0;}int[] dp new int[nums.length];dp[0] 1;int maxans 1;for (int i 1; i < dp.length; i) {int maxval …

Github(5)-开源开发-常见错误

使用github 托管代码简单使用教程--开源开发-常见错误5. github开源开发6. 报错log6.1 fatal: remote origin already exists.6.2 There is no tracking information for the current branch.6.标签管理廖雪峰老师博文学习笔记&#xff1a;https://www.liaoxuefeng.com/wiki/89…

online游戏服务器架构--数据库及事件相关 .

Online服务器的第三部分就是数据层&#xff0c;send_request_to_db开始了数据层的处理逻辑&#xff1a; int send_request_to_db(int cmd, sprite_t* p, int body_len, const void* body_buf, uint32_t id)&#xff1b; 在该函数里首先以懒惰的方式连接数据库服务器&#xff…

leecode5 最长回文子串

给定一个字符串 s&#xff0c;找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。 示例 1&#xff1a; 输入: "babad" 输出: "bab" 注意: "aba" 也是一个有效答案。 示例 2&#xff1a; 输入: "cbbd" 输出: "bb"…

libxml解析xml文件的一些总结

libxml -- 解析 XML 文档XML 介绍&#xff1a;XML 和 DOMlibxml 介绍 数据类型 — xmlChar数据结构 创建 XML 文档解析 XML 文档修改 xml 文档Xpath — 处理大型 XML 文档libxml2 库函数要注意的函数读取 xml 文件xml 操作基本结构及其指针类型根节点相关函数 创建子节点相关函…

Linux(7)-正则表达式

正则表达式demo1:在某个文件中寻找命令seddemo2:寻找8位电话号码正则表达式&#xff1a;用来描述或者匹配某一系列符合某个句法队则的字符串或者单个字符串。最初正则表达式&#xff0c;出现在自动控制理论和形式化语言理论中。 Linux 中 find grep sed ls命令都支持正则表达式…

服务器端开发的一些建议

摘要: 本文作为游戏服务器端开发的基本大纲&#xff0c;是游戏实践开发中的总结。第一部分专业基础&#xff0c;用于指导招聘和实习考核&#xff0c; 第二部分游戏入门&#xff0c;讲述游戏服务器端开发的基本要点&#xff0c;第三部分服务端架构&#xff0c;介绍架构设计中的一…

leetcode63 不同路径II

一个机器人位于一个 m x n 网格的左上角 &#xff08;起始点在下图中标记为“Start” &#xff09;。 机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角&#xff08;在下图中标记为“Finish”&#xff09;。 现在考虑网格中有障碍物。那么从左上角到右下角将…

小谈Online-game服务器端设计(1、2)

谈这个话题之前&#xff0c;首先要让大家知道&#xff0c;什么是服务器。在网络游戏中&#xff0c;服务器所扮演的角色是同步&#xff0c;广播和服务器主动的一些行为&#xff0c;比如说天气&#xff0c;NPC AI之类的&#xff0c;之所以现在的很多网络游戏服务器都需要负担一些…

Linux(8)-Linux下的编程开发-C/C++、PHP、JAVA概述

Linux下的编程开发1.C/C语言开发环境的搭建2.PHP开发环境搭建3.JAVA开发环境搭建1.C/C语言开发环境的搭建 方式1:文本编辑器编译器&#xff08;gcc/g&#xff09; Ubuntu 下常用的文本编辑器&#xff1a; Gedit–语法高亮Vim–vi(无比强大无比难用)的改进。字符界面/图形界面…

leetcode55 跳跃游戏 秒杀所有答案

给定一个非负整数数组&#xff0c;你最初位于数组的第一个位置。 数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个位置。 示例 1: 输入: [2,3,1,1,4] 输出: true 解释: 我们可以先跳 1 步&#xff0c;从位置 0 到达 位置 1, 然后再从位置 …

小谈Online-game服务器端设计(3)

下面我想来谈谈关于服务器上NPC的设计以及NPC智能等一些方面涉及到的问题。首先&#xff0c;我们需要知道什么是NPC&#xff0c;NPC需要做什么。NPC的全称是&#xff08;Non-Player Character&#xff09;&#xff0c;很显然&#xff0c;他是一个character&#xff0c;但不是玩…

小谈Online-game服务器端设计(4)

在这一章节&#xff0c;我想谈谈关于服务器端的脚本的相关设计。因为在上一章节里面&#xff0c;谈NPC智能相关的时候已经接触到一些脚本相关的东东了。还是先来谈谈脚本的作用吧。   在基于编译的服务器端程序中&#xff0c;是无法在程序的运行过程中构建一些东西的&#xf…

leetcode45 跳跃游戏II 秒杀所有答案

给定一个非负整数数组&#xff0c;你最初位于数组的第一个位置。 数组中的每个元素代表你在该位置可以跳跃的最大长度。 你的目标是使用最少的跳跃次数到达数组的最后一个位置。 示例: 输入: [2,3,1,1,4] 输出: 2 解释: 跳到最后一个位置的最小跳跃数是 2。 从下标为 …