C语言apr_socket,APR分析-高级IO篇
APR分析-高级IO篇
近两天稍轻闲了些,便抓紧时间学习、学习再学习。在“APR分析-文件IO篇”,我们只分析了最基本的I/O操作,如文件的open、close、write和read。当然File
I/O操作不止这些,在这一篇中我们来看看APR提供的一些高级I/O设施,包括记录锁、I/O多路复用和内存映射文件(内存映射文件将和共享内存一起分析)。
一、记录锁或(区域锁)[注1]
我见过的对记录锁讲解最详细的书就是《Unix高级环境编程》,特别是关于进程、文件描述符和记录锁三者之间关系的讲解更是让人受益匪浅,有此书的朋友一定不要放过哟。这里将其中的三原则摘录到这:
关于记录锁的自动继承和释放有三条规则:
(1)锁与进程、文件两方面有关。这有两重含意:第一重很明显,当一个进程终止时,它所建立的锁全部释放;第二重意思就不很明显,任何时候关闭一个描述符时,则该进程通过这一描述符可以存访的文件上的任何一把锁都被释放(这些锁都是该进程设置的)。
(2)由fork产生的子程序不继承父进程所设置的锁。这意味着,若一个进程得到一把锁,然后调用fork,那么对于父进程获得的锁而言,子进程被视为另一个进程,对于从父进程处继承过来的任一描述符,子进程要调用fcntl以获得它自己的锁。这与锁的作用是相一致的。锁的作用是阻止多个进程同时写同一个文件(或同一文件区域)。如果子进程继承父进程的锁,则父、子进程就可以同时写同一个文件。
(3)在执行exec后,新程序可以继承原执行程序的锁。
话归正题谈APR的记录锁,平心而论APR的提供的加索和解锁接口并没有什么独到的地方,APR之所以将之封装起来,无非是为了提供一个统一的跨平台接口,并且不破坏APR整体代码风格的一致性。APR记录锁源码位置在$(APR_HOME)/file_io/unix目录下flock.c,头文件仍然是apr_file_io.h。apr_file_lock和apr_file_unlock仅提供对整个文件的加锁和解锁,而并不支持对文件中任意范围数据的加锁和解锁。至于该锁是建议锁(advisory
lock)还是强制锁(mandatory lock),需要看具体的平台的实现了。两个函数均利用fcntl实现记录锁功能(前提是所在平台支持fcntl,由于fcntl是POSIX标准,绝大多数平台都支持)。代码中有一处值得鉴赏:
while ((rc = fcntl(thefile->filedes, fc, &l)) < 0&& errno == EINTR)
continue;
这里这么做的原因就是考虑到fcntl的调用可能被某信号中断,一旦中断我们去要重启fcntl函数。
二、I/O多路复用[注2]
在经典的《Unix网络编程第1卷》Chapter
6中作者详细介绍了五种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)
作者同时对这5种I/O模型作了很详细的对比分析,很值得一看。这里所说的I/O多路复用就是第三种模型,它既解决了Blocking
I/O数据处理不及时,又解决了Non-Blocking I/O采用轮旬的CPU浪费问题,同时它与异步I/O不同的是它得到了各大平台的广泛支持。
APR I/O多路复用源码主要在$(APR_HOME)/poll/unix目录下的poll.c和select.c中,头文件为apr_poll.h。APR提供统一的apr_poll接口,但是apr_pollset_t结构定义和apr_poll的实现则根据宏POLLSET_USES_SELECT、POLL_USES_POLL和POLLSET_USES_POLL的定义与否而不同。这里拿poll的实现(That
is使用poll来实现apr_poll及apr_pollset_xx相关,与之对应的是使用select来实现apr_poll及apr_pollset_xx相关)来分析:在poll的实现下,apr_pollset_t的定义如下:
/* in poll.c */
struct apr_pollset_t
{
apr_pool_t *pool;
apr_uint32_t nelts;
apr_uint32_t nalloc;
struct pollfd *pollset;
apr_pollfd_t *query_set;
apr_pollfd_t *result_set;
};
统一的apr_pollfd_t定义如下:
/* in apr_poll.h */
struct apr_pollfd_t {
apr_pool_t*p; /* associated pool */
apr_datatype_e desc_type; /*descriptor type */
apr_int16_treqevents; /* requested events */
apr_int16_trtnevents; /* returned events */
apr_descriptordesc; /* @see apr_descriptor */
void*client_data; /* allowsapp to associate context */
};
把数据结构定义贴出来便于后面分析时参照理解。
假设我们像这样apr_pollset_create(&mypollset,10, p, 0)调用,那么在apr_pollset_create后,我们可以用图示来表示mypollset变量的状态:
mypollset
-------
nalloc ----> 10 /*该mypollset的“容量”,在create的时候由参数指定*/
-------
nelts ----> 0 /*刚初始化,mypollset中并没有任何element,之后每add一次,nelts就+1
*/
-------
---------------------------------------------
pollset ---------> pollset[0] | pollset[1] |...|pollset[nalloc-1]
---------------------------------------------
-------
-----------------------------------------------------
query_set ---------> query_set[0] | query_set[1] |...|query_set[nalloc-1]
-----------------------------------------------------
-------
---------------------------------------------------------
result_set ---------> result_set[0] | result_set[1] |...|result_set[nalloc-1]
---------------------------------------------------------
-------
pollset、query_set和result_set这几个集合的关系通过下图说明:
apr_pollfd_t *descriptor ---> [pollset_add]--------> query_set ------ [pollset_poll] -----> result_set (输出)
| /|/
------------------->pollset ------ [pollset_poll] --------------------
apr_pollset_xx系列是改版后APR I/O复用新增的接口集,它以apr_pollset_t作为其管理的基本单位,其中apr_pollset_poll用于监视pollset中的所有descriptor(s)。而apr_poll则是旧版的APR
I/O复用接口,它同样可以实现apr_pollset_poll的功能,只是它的基本管理单位是apr_pollfd_t,其相关函数还包括apr_poll_setup、apr_poll_socket_add等在apr-1.1.1版中已看不到的几个接口。新版本中建议使用apr_pollset_poll,起码APR的测试用例(testpoll.c)是这么做的。
select实现的思路与poll实现的思路是一致的,只是apr_pollset_t的结构不同,原因不言自明。
三、总结
由于APR对高级I/O的封装很“薄”,所以基本上没有太多很精致的东西。
四、参考资料
1、《Unix高级环境编程》
2、《Unix网络编程卷1、2》
[注1]
对于Unix,“记录”这个定语也是误用,因为Unix内核根本没有使用文件记录这种概念。一个更适合的术语可能是“区域锁”,因为它锁定的只是文件的一个区域(也可能是整个文件)--摘自《Unix高级环境编程》。
[注2]
在《Unix网络编程卷1》译者译为"多路复用",在《Unix高级环境编程》中译者译为"多路转接",我更倾向于前者。I/O多路复用其英文为"I/OMultiplexing"。
C语言apr_socket,APR分析-高级IO篇相关推荐
- APR分析-共享内存篇
APR分析-共享内存篇 共享内存是一种重要的IPC方式.在项目中多次用到共享内存,只是用而并未深入研究.这次趁研究APR代码的机会复习了共享内存的相关资料. APR共享内存封装的源代码的位置在$(AP ...
- Linux性能分析之IO篇
硬盘IO篇 这里用到iostat用于分析磁盘IO的利器 iostat 3 10 的意思是每3秒检测一次,一共检测10次 %iowait 值得注意的一个地方,表示理论上越低表示磁盘越不繁忙. tps:每 ...
- linux系统资源分析 - 磁盘IO篇
目录 一.理解磁盘IO 二.普通文件IO调度 三.磁盘阵列 四.常用命令 4.1 iostat命令详解 五.综合案例(内存&IO) 一.理解磁盘IO 以超市结账为例,来理解磁盘IO的队列情况( ...
- android apr分析,APR分析信号篇
APR分析-信号篇 U know信号是Unix的重要系统机制.信号机制使用起来很简单,但是理解起来有并不是那么Easy.APR Signal的封装也并不繁琐,代码量很少,所以分析APR Signal的 ...
- 一个C语言的基本教程—IO篇
文章目录 10.与用户交互的关键--IO篇 (1).I/O是什么 (2).换个办法操作字符 #1.新的朋友--getchar和putchar #2.getchar的妙用 (3).重新认识一下--pri ...
- 50万数据生成6位数不重复字符串_R语言系列3:高级数据管理
R语言系列3:高级数据管理 此文内容为<R语言实战>的笔记,人民邮电出版社出版. 从高中电脑课学VB开始,大一课内开始学习C++,到后来大二为了数模学习Matlab,到大三为了搞深度学习自 ...
- Spring定时任务高级使用篇
Spring定时任务高级使用篇 前面一篇博文 <Spring之定时任务基本使用篇> 介绍了Spring环境下,定时任务的简单使用姿势,也留了一些问题,这一篇则希望能针对这些问题给个答案 I ...
- Linux之高级IO
目录 一.五种IO模型 以网络为例 什么叫做IO? 什么叫做高效的IO呢? 为什么第二个大爷的效率很高呢? 五种IO模型 感性认识 这五个人,在钓鱼的时候,谁的效率是最高的? 阻塞IO 非阻塞IO 信 ...
- c语言获取指针分配的字节数,c语言指针知识点总结(共6篇).docx
c语言指针知识点总结(共6篇) C语言指针教学中的知识点分析与总结 摘要:分析指针的基本概念及指针在数组.函数.字符串.动态存储分配等方面的应用,提出指针教学过程中易混淆概念及注意事项,对初学者深入理 ...
- Wireshark数据抓包分析(网络协议篇)第1章网络协议抓包概述
Wireshark数据抓包分析(网络协议篇)第1章网络协议抓包概述 网络协议是用于不同计算机之间进行网络通信的.网络协议是网络上所有设备(如网络服务器.计算机.交换机.路由器等)之间通信规则的集合,它 ...
最新文章
- Android 通过Intent调用系统功能和Action动作和服务广播【大全】
- 手機電視挑戰傳統視聽習慣
- 99. Leetcode 322. 零钱兑换 (动态规划-完全背包)
- Mysql5.7读写分离
- winmail计算机三级,2016年计算机三级网络技术机考模拟题(1)
- svm算法 java实现_SVM算法实现(一)
- QQ 可注销版本上线;拼多多成立技术顾问委员会;董明珠:建议偷手机判 10 年 | 极客头条...
- Java+selenium 自动化测试--自动化测试模型介绍
- 机器人伪装成人类在 GitHub 上为开源项目修复 bug
- linux下用arcconf做raid5,arcconf工具相关命令V1.0
- android8.1dolby,努比亚X刷杜比音效教程-按推理支持绝多数安卓8和安卓9系统
- hive Unexpected column vector type LIST
- 关于计算机的想象类作文,想象类作文范文
- QThread: Destroyed while thread is still running的处理方法
- luogu 4234 最小差值生成树 LCT
- 继昨天的猜拳游戏,升级为老虎机版
- debian重启ssh服务_Win10自带的ssh客户端key权限设置
- pythonGUI(二)基本元素之二
- 忽略validateRequest设置
- html左侧下拉输入选项菜单栏,怎么实现html可输入下拉菜单