环形缓冲区为什么是lock-free的?

环形缓冲区为什么是lock-free的?,第1张

回答这个问题之前,首先解释一下,什么叫lock-free?lock-free就是绝对无锁。那么为什么在环形缓冲区中不需要上锁呢?下面我将从三个方面来解释这个问题,首先先解释什么是环形缓冲区,然后再来了解lock-free的三个必要前提,最后才解释在环形缓冲区绝对无锁的原因。

环形缓冲区的本质

所谓的环形缓冲区,其实就是使用一个环形的缓冲区域作为数据循环结构。可以插入数据、删除数据,通过改变了队列中的首尾来达到空间的分配和释放。

lock-free的三个前提

这其中有三个前提,一是cpu支持内存栅栏,二是数据的地址必须是四对齐的,三是必须是一个生产者对应一个消费者。这三个必要前提缺一不可,否则就没有办法实现lock-free了。

lock-free存在的原因

所谓的环形缓冲区实际上就相当于一个队列,在这个队列中,只有一个生产者和一个消费者,但是不管是生产者还是消费者,都不需要完全独自霸占整个队列,他们都只是移动首尾,也就是数据的输入和删除,变化的只是环形缓冲区中空间的位置分配。所以不存在满的情况,也不需要对整个数据结构进行加锁。

以上就是我对这个问题的简单解释。因个人经验有限,所以其中有问题的地方,也欢迎大家指出。

Windows网络与通信程序设计(第2版) 王艳平 这本书写的非常好,我有本王艳平写的 windows程序设计,写得很好,我自己不做网络开发,就没有买网络的那本书!不过推荐你看看,真的很不错!

本书将编程方法、网络协议和应用实例有机结合起来,详细阐明Windows网络编程的各方面内容。本书首先介绍Windows平台上进行网络编程的基础知识,包括网络硬件、术语、协议、Winsock编程接口和各种I/O方法等;然后通过具体实例详细讲述当前流行的高性能可伸缩服务器设计、IP多播和Internet广播、P2P程序设计、原始套接字、SPI、协议驱动的开发和原始以太数据的发送、ARP欺骗技术、LAN和WAN上的扫描和侦测技术、个人防火墙与网络封包截获技术等;最后讲述IP帮助函数和E-mail的开发方法。 本书结构紧凑,内容由浅入

第1章 计算机网络基础 1

11 网络的概念和网络的组成 1

12 计算机网络参考模型 2

121 协议层次 2

122 TCP/IP参考模型 2

123 应用层(Application Layer) 3

124 传输层(Transport Layer) 3

125 网络层(Network Layer) 3

126 链路层(Link Layer) 4

127 物理层(Physical Layer) 4

13 网络程序寻址方式 4

131 MAC地址 4

132 IP地址 5

133 子网寻址 6

134 端口号 8

135 网络地址转换(NAT) 8

14 网络应用程序设计基础 10

141 网络程序体系结构 10

142 网络程序通信实体 11

143 网络程序开发环境 12

第2章 Winsock编程接口 13

21 Winsock库 13

211 Winsock库的装入和释放 13

212 封装CInitSock类 14

22 Winsock的寻址方式和字节顺序 14

221 Winsock寻址 14

222 字节顺序 16

223 获取地址信息 17

23 Winsock编程详解 20

231 Winsock编程流程 20

232 典型过程图 23

233 TCP服务器和客户端程序举例 24

234 UDP编程 26

24 网络对时程序实例 28

241 时间协议(Time Protocol) 28

242 TCP/IP实现代码 29

第3章 Windows套接字I/O模型 31

31 套接字模式 31

311 阻塞模式 31

312 非阻塞模式 31

32 选择(select)模型 32

321 select函数 32

322 应用举例 33

33 WSAAsyncSelect模型 36

331 消息通知和WSAAsyncSelect函数 36

332 应用举例 37

34 WSAEventSelect模型 40

341 WSAEventSelect函数 40

342 应用举例 42

343 基于WSAEventSelect模型的服务器设计 44

35 重叠(Overlapped)I/O模型 53

351 重叠I/O函数 53

352 事件通知方式 56

353 基于重叠I/O模型的服务器设计 56

第4章 IOCP与可伸缩网络程序 67

41 完成端口I/O模型 67

411 什么是完成端口(completion port)对象 67

412 使用IOCP的方法 67

413 示例程序 69

414 恰当地关闭IOCP 72

42 Microsoft扩展函数 72

421 GetAcceptExSockaddrs函数 73

422 TransmitFile函数 73

423 TransmitPackets函数 74

424 ConnectEx函数 75

425 DisconnectEx函数 76

43 可伸缩服务器设计注意事项 76

431 内存资源管理 76

432 接受连接的方法 77

433 恶意客户连接问题 77

434 包重新排序问题 78

44 可伸缩服务器系统设计实例 78

441 CIOCPServer类的总体结构 78

442 数据结构定义和内存池方案 82

443 自定义帮助函数 85

444 开启服务和停止服务 88

445 I/O处理线程 93

446 用户接口和测试程序 99

第5章 互联网广播和IP多播 100

51 套接字选项和I/O控制命令 100

511 套接字选项 100

512 I/O控制命令 102

52 广播通信 103

53 IP多播(Multicasting) 105

531 多播地址 105

532 组管理协议(IGMP) 105

533 使用IP多播 106

54 基于IP多播的组讨论会实例 110

541 定义组讨论会协议 110

542 线程通信机制 111

543 封装CGroupTalk类 111

544 程序界面 117

第6章 原始套接字 121

61 使用原始套接字 121

62 ICMP编程 121

621 ICMP与校验和的计算 121

622 Ping程序实例 124

623 路由跟踪 126

63 使用IP头包含选项 129

631 IP数据报格式 129

632 UDP数据报格式 131

633 原始UDP封包发送实例 133

64 网络嗅探器开发实例 134

641 嗅探器设计原理 135

642 网络嗅探器的具体实现 136

643 侦听局域网内的密码 138

65 TCP通信开发实例 140

651 创建一个原始套接字,并设置IP头选项 140

652 构造IP头和TCP头 140

653 发送原始套接字数据报 142

654 接收数据 146

第7章 Winsock服务提供者接口(SPI) 147

71 SPI概述 147

72 Winsock协议目录 148

721 协议特性 149

722 使用Winsock API函数枚举协议 150

723 使用Winsock SPI函数枚举协议 151

73 分层服务提供者(LSP) 153

731 运行原理 153

732 安装LSP 154

733 移除LSP 158

734 编写LSP 159

735 LSP实例 161

74 基于SPI的数据报过滤实例 165

75 基于Winsock的网络聊天室开发 171

751 服务端 171

752 客户端 171

753 聊天室程序的设计说明 172

754 核心代码分析 172

第8章 Windows网络驱动接口标准(NDIS)和协议驱动的开发 176

81 核心层网络驱动 176

811 Windows 2000及其后产品的网络体系结构 176

812 NDIS网络驱动程序 177

813 网络驱动开发环境 178

82 WDM驱动开发基础 181

821 UNICODE字符串 181

822 设备对象 181

823 驱动程序的基本结构 183

824 I/O请求包(I/O request packet,IRP)和I/O堆栈 183

825 完整驱动程序示例 186

826 扩展派遣接口 188

827 应用举例(进程诊测实例) 191

83 开发NDIS网络驱动预备知识 198

831 中断请求级别(Interrupt Request Level,IRQL) 198

832 旋转锁(Spin Lock) 198

833 双链表 199

834 封包结构 199

84 NDIS协议驱动 200

841 注册协议驱动 200

842 打开下层协议驱动的适配器 201

843 协议驱动的封包管理 202

844 在协议驱动中接收数据 203

845 从协议驱动发送封包 204

85 NDIS协议驱动开发实例 204

851 总体设计 204

852 NDIS协议驱动的初始化、注册和卸载 206

853 下层NIC的绑定和解除绑定 209

854 发送数据 217

855 接收数据 219

856 用户IOCTL处理 225

第9章 网络扫描与检测技术 233

91 网络扫描基础知识 233

911 以太网数据帧 233

912 ARP 234

913 ARP格式 236

914 SendARP函数 237

92 原始以太封包的发送 238

921 安装协议驱动 238

922 协议驱动用户接口 238

923 发送以太封包的测试程序 244

93 局域网计算机扫描 245

931 管理原始ARP封包 246

932 ARP扫描示例 249

94 互联网计算机扫描 253

941 端口扫描原理 253

942 半开端口扫描实现 254

95 ARP欺骗原理与实现 259

951 IP欺骗的用途和实现原理 259

952 IP地址冲突 260

953 ARP欺骗示例 261

第10章 点对点(P2P)网络通信技术 264

101 P2P穿越概述 264

102 一般概念 265

1021 NAT术语 265

1022 中转 265

1023 反向连接 266

103 UDP打洞 267

1031 中心服务器 267

1032 建立点对点会话 267

1033 公共NAT后面的节点 267

1034 不同NAT后面的节点 268

1035 多级NAT后面的节点 269

1036 UDP空闲超时 270

104 TCP打洞 271

1041 套接字和TCP端口重用 271

1042 打开点对点的TCP流 271

1043 应用程序看到的行为 272

1044 同步TCP打开 273

105 Internet点对点通信实例 273

1051 总体设计 273

1052 定义P2P通信协议 274

1053 客户方程序 275

1054 服务器方程序 287

1055 测试程序 291

第11章 核心层网络封包截获技术 294

111 Windows网络数据和封包过滤概述 294

1111 Windows网络系统体系结构图 294

1112 用户模式下的网络数据过滤 295

1113 内核模式下的网络数据过滤 296

112 中间层网络驱动PassThru 296

1121 PassThru NDIS中间层驱动简介 296

1122 编译和安装PassThru驱动 297

113 扩展PassThru NDIS IM驱动——添加IOCTL接口 297

1131 扩展之后的PassThru驱动(PassThruEx)概况 297

1132 添加基本的DeviceIoControl接口 298

1133 添加绑定枚举功能 302

1134 添加ADAPT结构的引用计数 307

1135 适配器句柄的打开/关闭函数 308

1136 句柄事件通知 315

1137 查询和设置适配器的OID信息 315

114 扩展PassThru NDIS IM驱动——添加过滤规则 323

1141 需要考虑的事项 323

1142 过滤相关的数据结构 324

1143 过滤列表 326

1144 网络活动状态 327

1145 IOCTL控制代码 328

1146 过滤数据 331

115 核心层过滤实例 339

第12章 Windows网络防火墙开发技术 342

121 防火墙技术概述 342

122 金羽(Phoenix)个人防火墙浅析 343

1221 金羽(Phoenix)个人防火墙简介 343

1222 金羽(Phoenix)个人防火墙总体设计 344

1223 金羽(Phoenix)个人防火墙总体结构 345

123 开发前的准备 345

1231 常量的定义 346

1232 访问规则 348

1233 会话结构 348

1234 文件结构 349

1235 UNICODE支持 355

124 应用层DLL模块 356

1241 DLL工程框架 356

1242 共享数据和IO控制 362

1243 访问控制列表ACL(Access List) 364

1244 查找应用程序访问权限的过程 367

1245 类的接口——检查函数 370

125 核心层SYS模块 373

126 主模块工程 375

1261 I/O控制类 375

1262 主应用程序类 377

1263 主对话框中的属性页 380

1264 主窗口类 381

127 防火墙页面 383

1271 网络访问监视页面 383

1272 应用层过滤规则页面 387

1273 核心层过滤规则页面 397

1274 系统设置页面 403

第13章 IP帮助函数 406

131 IP配置信息 406

1311 获取网络配置信息 406

1312 管理网络接口 408

1313 管理IP地址 412

132 获取网络状态信息 415

1321 获取TCP连接表 415

1322 获取UDP监听表 418

1323 获取IP统计数据 420

133 路由管理 427

1331 获取路由表 427

1332 管理特定路由 431

1333 修改默认网关的例子 432

134 ARP表管理 433

1341 获取ARP表 433

1342 添加ARP入口 434

1343 删除ARP入口 434

1344 打印ARP表的例子 434

135 进程网络活动监视实例 438

1351 获取通信的进程终端 438

1352 Netstate源程序代码 439

第14章 Email协议及其编程 444

141 概述 444

142 电子邮件介绍 445

1421 电子邮件Internet的地址 445

1422 Internet邮件系统 445

1423 电子邮件信头的结构及分析 446

143 SMTP原理 448

1431 SMTP原理分析 448

1432 SMTP工作机制 449

1433 SMTP命令码和工作原理 449

1434 SMTP通信模型 450

1435 SMTP的命令和应答 451

144 POP3协议原理 452

1441 POP3协议简介 452

1442 POP3工作原理 453

1443 POP3命令原始码 454

1444 POP3会话实例 459

145 实例分析与程序设计 460

1451 总界面设计 460

1452 SMTP客户端设计 461

1453 POP3客户端设计 473

对这一行不熟悉不敢乱判断。猜测一下可能的原因:

如果用windows当服务器,IOCP很成熟所以选择C++

C#本身带有内存回收机制,对于某些类型的服务器需要自己管理内存回收

技术上没问题,听说过用C#当网页游戏服务器的成功案例

用C#的成本在这一行不算低(综合服务器,开发效率,招人难度等)

现成有许多成熟的公司框架不需要自己重新写,大家跳跳槽也都有了……

(一)首先,介绍几种常见的I/O模型及其区别,如下:

blocking I/O

nonblocking I/O

I/O multiplexing (select and poll)

signal driven I/O (SIGIO)

asynchronous I/O (the POSIX aio_functions)—————异步IO模型最大的特点是 完成后发回通知。

阻塞与否,取决于实现IO交换的方式。

异步阻塞是基于select,select函数本身的实现方式是阻塞的,而采用select函数有个好处就是它可以同时监听多个文件句柄

异步非阻塞直接在完成后通知,用户进程只需要发起一个IO操作然后立即返回,等IO操作真正的完成以后,应用程序会得到IO操作完成的通知,此时用户进程只需要对数据进行处理就好了,不需要进行实际的IO读写操作,因为真正的IO读取或者写入操作已经由内核完成了。

1 blocking I/O

这个不用多解释吧,阻塞套接字。下图是它调用过程的图示:

重点解释下上图,下面例子都会讲到。首先application调用 recvfrom()转入kernel,注意kernel有2个过程,wait for data和copy data from kernel to user。直到最后copy complete后,recvfrom()才返回。此过程一直是阻塞的。

2 nonblocking I/O:

与blocking I/O对立的,非阻塞套接字,调用过程图如下:

可以看见,如果直接操作它,那就是个轮询。。直到内核缓冲区有数据。

3 I/O multiplexing (select and poll)

最常见的I/O复用模型,select。

select先阻塞,有活动套接字才返回。与blocking I/O相比,select会有两次系统调用,但是select能处理多个套接字。

4 signal driven I/O (SIGIO)

只有UNIX系统支持,感兴趣的课查阅相关资料

与I/O multiplexing (select and poll)相比,它的优势是,免去了select的阻塞与轮询,当有活跃套接字时,由注册的handler处理。

5 asynchronous I/O (the POSIX aio_functions)

很少有nix系统支持,windows的IOCP则是此模型

完全异步的I/O复用机制,因为纵观上面其它四种模型,至少都会在由kernel copy data to appliction时阻塞。而该模型是当copy完成后才通知application,可见是纯异步的。好像只有windows的完成端口是这个模型,效率也很出色。

6 下面是以上五种模型的比较

可以看出,越往后,阻塞越少,理论上效率也是最优。

=====================分割线==================================

5种模型的比较比较清晰了,剩下的就是把select,epoll,iocp,kqueue按号入座那就OK了。

select和iocp分别对应第3种与第5种模型,那么epoll与kqueue呢?其实也于select属于同一种模型,只是更高级一些,可以看作有了第4种模型的某些特性,如callback机制。

为什么epoll,kqueue比select高级?

答案是,他们无轮询。因为他们用callback取代了。想想看,当套接字比较多的时候,每次select()都要通过遍历FD_SETSIZE个Socket来完成调度,不管哪个Socket是活跃的,都遍历一遍。这会浪费很多CPU时间。如果能给套接字注册某个回调函数,当他们活跃时,自动完成相关操作,那就避免了轮询,这正是epoll与kqueue做的。

windows or nix (IOCP or kqueue/epoll)?

诚然,Windows的IOCP非常出色,目前很少有支持asynchronous I/O的系统,但是由于其系统本身的局限性,大型服务器还是在UNIX下。而且正如上面所述,kqueue/epoll 与 IOCP相比,就是多了一层从内核copy数据到应用层的阻塞,从而不能算作asynchronous I/O类。但是,这层小小的阻塞无足轻重,kqueue与epoll已经做得很优秀了。

提供一致的接口,IO Design Patterns

实际上,不管是哪种模型,都可以抽象一层出来,提供一致的接口,广为人知的有ACE,Libevent(基于reactor模式)这些,他们都是跨平台的,而且他们自动选择最优的I/O复用机制,用户只需调用接口即可。说到这里又得说说2个设计模式,Reactor and Proactor。见:Reactor模式--VS--Proactor模式。Libevent是Reactor模型,ACE提供Proactor模型。实际都是对各种I/O复用机制的封装。

Java nio包是什么I/O机制?

现在可以确定,目前的java本质是select()模型,可以检查/jre/bin/niodll得知。至于java服务器为什么效率还不错。。我也不得而知,可能是设计得比较好吧。。-_-。

=====================分割线==================================

总结一些重点:

只有IOCP是asynchronous I/O,其他机制或多或少都会有一点阻塞。

select低效是因为每次它都需要轮询。但低效也是相对的,视情况而定,也可通过良好的设计改善

epoll, kqueue、select是Reacor模式,IOCP是Proactor模式。

java nio包是select模型。。

(二)epoll 与select的区别

1 使用多进程或者多线程,但是这种方法会造成程序的复杂,而且对与进程与线程的创建维护也需要很多的开销。(Apache服务器是用的子进程的方式,优点可以隔离用户) (同步阻塞IO)

2一种较好的方式为I/O多路转接(I/O multiplexing)(貌似也翻译多路复用),先构造一张有关描述符的列表(epoll中为队列),然后调用一个函数,直到这些描述符中的一个准备好时才返回,返回时告诉进程哪些I/O就绪。select和epoll这两个机制都是多路I/O机制的解决方案,select为POSIX标准中的,而epoll为Linux所特有的。

区别(epoll相对select优点)主要有三:

1select的句柄数目受限,在linux/posix_typesh头文件有这样的声明:#define __FD_SETSIZE 1024 表示select最多同时监听1024个fd。而epoll没有,它的限制是最大的打开文件句柄数目。

2epoll的最大好处是不会随着FD的数目增长而降低效率,在selec中采用轮询处理,其中的数据结构类似一个数组的数据结构,而epoll是维护一个队列,直接看队列是不是空就可以了。epoll只会对"活跃"的socket进行操作---这是因为在内核实现中epoll是根据每个fd上面的callback函数实现的。那么,只有"活跃"的socket才会主动的去调用 callback函数(把这个句柄加入队列),其他idle状态句柄则不会,在这点上,epoll实现了一个"伪"AIO。但是如果绝大部分的I/O都是“活跃的”,每个I/O端口使用率很高的话,epoll效率不一定比select高(可能是要维护队列复杂)。

3使用mmap加速内核与用户空间的消息传递。无论是select,poll还是epoll都需要内核把FD消息通知给用户空间,如何避免不必要的内存拷贝就很重要,在这点上,epoll是通过内核于用户空间mmap同一块内存实现的。

关于epoll工作模式ET,LT

epoll有两种工作方式

ET:Edge Triggered,边缘触发。仅当状态发生变化时才会通知,epoll_wait返回。换句话,就是对于一个事件,只通知一次。且只支持非阻塞的socket。

LT:Level Triggered,电平触发(默认工作方式)。类似select/poll,只要还有没有处理的事件就会一直通知,以LT方式调用epoll接口的时候,它就相当于一个速度比较快的poll支持阻塞和不阻塞的socket。

三 Linux并发网络编程模型

1 Apache 模型,简称 PPC ( Process Per Connection ,):为每个连接分配一个进程。主机分配给每个连接的时间和空间上代价较大,并且随着连接的增多,大量进程间切换开销也增长了。很难应对大量的客户并发连接。

2 TPC 模型( Thread Per Connection ):每个连接一个线程。和PCC类似。

3 select 模型:I/O多路复用技术。

1 每个连接对应一个描述。select模型受限于 FD_SETSIZE即进程最大打开的描述符数linux2635为1024,实际上linux每个进程所能打开描数字的个数仅受限于内存大小,然而在设计select的系统调用时,却是参考FD_SETSIZE的值。可通过重新编译内核更改此值,但不能根治此问题,对于百万级的用户连接请求 即便增加相应 进程数, 仍显得杯水车薪呀。

2select每次都会扫描一个文件描述符的集合,这个集合的大小是作为select第一个参数传入的值。但是每个进程所能打开文件描述符若是增加了 ,扫描的效率也将减小。

3内核到用户空间,采用内存复制传递文件描述上发生的信息。

4 poll 模型:I/O多路复用技术。poll模型将不会受限于FD_SETSIZE,因为内核所扫描的文件 描述符集合的大小是由用户指定的,即poll的第二个参数。但仍有扫描效率和内存拷贝问题。

5 pselect模型:I/O多路复用技术。同select。

6 epoll模型:

1)无文件描述字大小限制仅与内存大小相关

2)epoll返回时已经明确的知道哪个socket fd发生了什么事件,不用像select那样再一个个比对。

3)内核到用户空间采用共享内存方式,传递消息。

四 :FAQ

1、单个epoll并不能解决所有问题,特别是你的每个操作都比较费时的时候,因为epoll是串行处理的。 所以你有还是必要建立线程池来发挥更大的效能。

2、如果fd被注册到两个epoll中时,如果有时间发生则两个epoll都会触发事件。

3、如果注册到epoll中的fd被关闭,则其会自动被清除出epoll监听列表。

4、如果多个事件同时触发epoll,则多个事件会被联合在一起返回。

5、epoll_wait会一直监听epollhup事件发生,所以其不需要添加到events中。

6、为了避免大数据量io时,et模式下只处理一个fd,其他fd被饿死的情况发生。linux建议可以在fd联系到的结构中增加ready位,然后epoll_wait触发事件之后仅将其置位为ready模式,然后在下边轮询ready fd列表。

Nginx 结合FastCGI 程序可以搭建高性能web service程序。(a)Nginx不支持对外部程序的直接调用或者解析,所有的外部程序(包括PHP)必须通过FastCGI接口来调用。FastCGI接口在Linux下是socket(这个socket可以是文件socket,也可以是ip socket)。为了调用CGI程序,还需要一个FastCGI的wrapper(wrapper可以理解为用于启动另一个程序的程序),这个wrapper绑定在某个固定socket上,如端口或者文件socket。(b)当Nginx将CGI请求发送给这个socket的时候,通过FastCGI接口,wrapper接收到请求,然后派生出一个新的线程,这个线程调用解释器或者外部程序处理脚本并读取返回数据;接着,wrapper再将返回的数据通过FastCGI接口,沿着固定的socket传递给Nginx;最后,Nginx将返回的数据发送给客户端。这就是Nginx+FastCGI的整个运作过程,如图1所示。FastCGI接口方式在脚本解析服务器(CGI应用程序服务器)上启动一个或者多个守护进程对动态脚本进行解析,这些进程就是FastCGI进程管理器,或者称为FastCGI引擎。 spawn-fcgi与PHP-FPM都是FastCGI进程管理器(支持PHP和C/C++)。

DABAN RP主题是一个优秀的主题,极致后台体验,无插件,集成会员系统
网站模板库 » 环形缓冲区为什么是lock-free的?

0条评论

发表评论

提供最优质的资源集合

立即查看 了解详情