[AUPE chapter 14] 高级IO
2016-11-06 15:49
211 查看
作者:isshe
日期:2016.10.30
邮箱:i.sshe@outlook.com
github: https://github.com/isshe
a2. 与磁盘I/O有关的系统调用的相关描述?
a3. 如何指定非阻塞I/O?
b2. 对于记录锁相关的fcntl函数。
b3. 关于加锁解锁区域的说明和注意事项。
b4. 锁的隐含继承和释放3原则。
b0. 注意事项。
[b]1.1.3 readv和writev[/b]
c1.readv和writev介绍。
d0.注意事项
读操作,如果某些文件类型(读管道、终端设备、网络设备)的数据不存在。
写操作,如果数据不能被相同的文件类型立即接受(如管道无中间空间、网络流控制)
在某种条件发生之前打开某些文件类型可能会发生阻塞。(不大理解这个)
对已经加上强制性记录锁的文件进行读写。
某些ioctl操作。
某些进程间通信函数。(15章)
a2. 不能将与磁盘I/O有关的系统调用视为“低速”,尽管读写磁盘文件会暂时阻塞调用者。
a3. 指定非阻塞的I/O的方法:
指定O_NONBLOCK标志调用open获取描述符。
已打开的描述符,用O_NONBLOCK标志调用fcntl。(apue chapter3的3-12图)
注意:非阻塞I/O常使用轮询的方法,会造成量非CPU时间。有时可用多线程代替非阻塞I/O,但是要考虑线程间同步的开销以及复杂程度。(当然还可以用下面的高级I/O)
当第一个进程在读或修改文件的某个部分时,使用记录锁可以组织其他进程修改同一文件区。(记录锁更合适的术语是:字节范围锁(byte-range-locking)
b2. 对于记录锁相关的fcntl函数:
原型:
参数:
cmd:记录锁相关:
F_GETLK: 判断由flockptr所描述的锁是否被另外一把锁所排斥。(如无锁,则l_type = F_UNLCK)
F_SETLK: 设置由flockptr所描述的锁,或者清除锁(l_type = F_UNLCK)。
F_SETLKW: (W代表wait)F_SETLK的阻塞版本。当锁无法设置的时候,休眠等待锁可用再唤醒。
第3个参数:使用一个指向flock结构的指针,结构内容如下:
b3. 关于加锁解锁区域的说明和注意事项:
指定区域起始偏移量的两个元素(l_whence, l_start)和lseek函数的最后两个参数类似。
锁可以在当前文件的尾端处开始 或 越过尾端处开始, 但不能在文件起始位置之前开始。
l_len== 0, 表示锁的方位可以扩大到最大可能偏移量。
对整个文件加锁,设置l_whence和l_start指向文件起始,并指定l_len=0。(_l_whence = SEEK_SET, l_start = 0)
同一进程对文件同一区域多次加锁,则只保留最新的(前一次总被后一次替换)。
加读/写锁时,该描述符必须是读/写打开的。
b4. 锁的隐含继承和释放有3条规则:
锁与进程和文件两者相关联。
当进程终止时,它所建立的所有锁都被释放。
当关闭一个描述符时,它关联的文件上的任何一把锁都被释放(这些锁都是该进程建立的)(例如进程中有两个fd0,fd1某个文件的两次打开,当在其中一个lock后,另一个如果关闭,此lock也会被关闭)
由fork产生的子进程不继承父进程锁设置的锁。
在执行exec后,新程序可以继承原程序的锁。(如果设置执行时关闭标志,则锁会被释放)
b0. 注意事项:
1.用F_GETLK测试能否建立一把锁,然后用F_SETLK或F_SETLKW尝试建立那把锁。
2.如果不希望在等待锁变为可用时阻塞,就必须处理由F_SETLK返回的可能的错误。
原型:
功能:用于一次函数调用读/写多个非连续缓冲区。(散布读,聚集写)
参数:
fd:文件描述符。
iov:struct iovec数组,个数由iovcnt指定,最大值受限于IOV_MAX(图2-11)。
返回:已读/已写的字节数,出错返回-1。
c0. 注意事项:
* 原型:
功能:将一个给定的文件映射到一个存储区域中。
参数:
addr:指定映射存储区的起始地址(函数返回值通常也是这个)。如果addr == 0, 则由系统选择。
fd:指定要被映射的文件的描述符。(在文件映射前,必须先打开文件)
length:映射的字节数。
offset:要映射字节在文件中的偏移。
prot:指定映射存储区的保护要求。(不能超过open模式访问权限)
flags:影响映射存储区的多种属性:
MAP_FIXED:返回值必须是addr。(不鼓励使用,因为不利于可移植性)
MAP_SHARED:映射存储区是共享的,存储操作会直接作用到文件。
MAP_PRIVATE:对映射区的存储操作(write)导致创建该映射文件的一个副本,所有后来对该映射区的引用都引用该副本。任何修改只影响副本,不影响原文件(常用于调试程序,p424)
不同实现可能还有不同的MAP_XXX。
d0. 注意事项:
offset和addr的值,通常被要求是系统虚拟存储页长度的倍数。(页长通过_SC_PAGESIZE 或 _SC_PAGE_SIZE的sysconf函数获取)(offset和addr常常为0,所以这种要求一般不重要)
子进程能通过fork继承映射存储区。
关闭文件描述符并不解除映射存储区。
mprotect:更改现有映射的权限。
msync:冲洗共享映射中的修改页到被映射的文件中。
munmp:解除映射。(对共享映射,文件的更新会根据系统算法更新到文件,对MAP_PRIVATE映射,丢弃修改)
ubuntu16.04 man pages
日期:2016.10.30
邮箱:i.sshe@outlook.com
github: https://github.com/isshe
1. 基础知识
1.1 问题
1.1.1 非阻塞I/O
a1. 什么是[b]低速系统调用?都有哪些?[/b]a2. 与磁盘I/O有关的系统调用的相关描述?
a3. 如何指定非阻塞I/O?
1.1.2 记录锁
b1. 记录锁的功能是什么?b2. 对于记录锁相关的fcntl函数。
b3. 关于加锁解锁区域的说明和注意事项。
b4. 锁的隐含继承和释放3原则。
b0. 注意事项。
[b]1.1.3 readv和writev[/b]
c1.readv和writev介绍。
1.1.4 存储映射I/O
d1.mmap函数介绍。d0.注意事项
1.2 解答
1. 2.1 非阻塞I/O
a1. 低速系统调用:可能会使进程永远阻塞的一类系统调用,包括:读操作,如果某些文件类型(读管道、终端设备、网络设备)的数据不存在。
写操作,如果数据不能被相同的文件类型立即接受(如管道无中间空间、网络流控制)
在某种条件发生之前打开某些文件类型可能会发生阻塞。(不大理解这个)
对已经加上强制性记录锁的文件进行读写。
某些ioctl操作。
某些进程间通信函数。(15章)
a2. 不能将与磁盘I/O有关的系统调用视为“低速”,尽管读写磁盘文件会暂时阻塞调用者。
a3. 指定非阻塞的I/O的方法:
指定O_NONBLOCK标志调用open获取描述符。
已打开的描述符,用O_NONBLOCK标志调用fcntl。(apue chapter3的3-12图)
注意:非阻塞I/O常使用轮询的方法,会造成量非CPU时间。有时可用多线程代替非阻塞I/O,但是要考虑线程间同步的开销以及复杂程度。(当然还可以用下面的高级I/O)
1.2.2 记录锁
b1. 记录锁(record locking)的功能是:当第一个进程在读或修改文件的某个部分时,使用记录锁可以组织其他进程修改同一文件区。(记录锁更合适的术语是:字节范围锁(byte-range-locking)
b2. 对于记录锁相关的fcntl函数:
原型:
#include <unistd.h> #include <fcntl.h> //注意第3个参数 int fcntl(int fd, int cmd, ... /* struct flock *flockptr */ );
参数:
cmd:记录锁相关:
F_GETLK: 判断由flockptr所描述的锁是否被另外一把锁所排斥。(如无锁,则l_type = F_UNLCK)
F_SETLK: 设置由flockptr所描述的锁,或者清除锁(l_type = F_UNLCK)。
F_SETLKW: (W代表wait)F_SETLK的阻塞版本。当锁无法设置的时候,休眠等待锁可用再唤醒。
第3个参数:使用一个指向flock结构的指针,结构内容如下:
struct flock { ... short l_type; /* 锁类型: F_RDLCK(共享读锁), F_WRLCK(独占写锁), F_UNLCK(解锁一个区域 */ short l_whence; /* 和l_start配合,l_whence取值: SEEK_SET, SEEK_CUR, SEEK_END */ off_t l_start; /* 锁定区域的开始 *偏移*!*/ off_t l_len; /* 区域的字节长度 */ pid_t l_pid; /* PID为pid的进程持有的锁可以阻塞当前进程 (set by F_GETLK and F_OFD_GETLK) */ ... };
b3. 关于加锁解锁区域的说明和注意事项:
指定区域起始偏移量的两个元素(l_whence, l_start)和lseek函数的最后两个参数类似。
锁可以在当前文件的尾端处开始 或 越过尾端处开始, 但不能在文件起始位置之前开始。
l_len== 0, 表示锁的方位可以扩大到最大可能偏移量。
对整个文件加锁,设置l_whence和l_start指向文件起始,并指定l_len=0。(_l_whence = SEEK_SET, l_start = 0)
同一进程对文件同一区域多次加锁,则只保留最新的(前一次总被后一次替换)。
加读/写锁时,该描述符必须是读/写打开的。
b4. 锁的隐含继承和释放有3条规则:
锁与进程和文件两者相关联。
当进程终止时,它所建立的所有锁都被释放。
当关闭一个描述符时,它关联的文件上的任何一把锁都被释放(这些锁都是该进程建立的)(例如进程中有两个fd0,fd1某个文件的两次打开,当在其中一个lock后,另一个如果关闭,此lock也会被关闭)
由fork产生的子进程不继承父进程锁设置的锁。
在执行exec后,新程序可以继承原程序的锁。(如果设置执行时关闭标志,则锁会被释放)
b0. 注意事项:
1.用F_GETLK测试能否建立一把锁,然后用F_SETLK或F_SETLKW尝试建立那把锁。
2.如果不希望在等待锁变为可用时阻塞,就必须处理由F_SETLK返回的可能的错误。
1.2.3 readv和writev
c1.readv和writev介绍:原型:
#include <sys/uio.h> ssize_t readv(int fd, const struct iovec *iov, int iovcnt); ssize_t writev(int fd, const struct iovec *iov, int iovcnt); //结构: struct iovec { void *iov_base; /* Starting address */ size_t iov_len; /* Number of bytes to transfer */ };
功能:用于一次函数调用读/写多个非连续缓冲区。(散布读,聚集写)
参数:
fd:文件描述符。
iov:struct iovec数组,个数由iovcnt指定,最大值受限于IOV_MAX(图2-11)。
返回:已读/已写的字节数,出错返回-1。
c0. 注意事项:
1.2.4 存储映射I/O
d1.mmap函数介绍* 原型:
#include <sys/mman.h> void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
功能:将一个给定的文件映射到一个存储区域中。
参数:
addr:指定映射存储区的起始地址(函数返回值通常也是这个)。如果addr == 0, 则由系统选择。
fd:指定要被映射的文件的描述符。(在文件映射前,必须先打开文件)
length:映射的字节数。
offset:要映射字节在文件中的偏移。
prot:指定映射存储区的保护要求。(不能超过open模式访问权限)
prot | 说明 |
---|---|
PROT_READ | 映射区可读 |
PROT_WRITE | 映射区可写 |
PROT_EXEC | 映射区可执行 |
PROT_NONE | 映射区不可访问 |
MAP_FIXED:返回值必须是addr。(不鼓励使用,因为不利于可移植性)
MAP_SHARED:映射存储区是共享的,存储操作会直接作用到文件。
MAP_PRIVATE:对映射区的存储操作(write)导致创建该映射文件的一个副本,所有后来对该映射区的引用都引用该副本。任何修改只影响副本,不影响原文件(常用于调试程序,p424)
不同实现可能还有不同的MAP_XXX。
d0. 注意事项:
offset和addr的值,通常被要求是系统虚拟存储页长度的倍数。(页长通过_SC_PAGESIZE 或 _SC_PAGE_SIZE的sysconf函数获取)(offset和addr常常为0,所以这种要求一般不重要)
子进程能通过fork继承映射存储区。
关闭文件描述符并不解除映射存储区。
mprotect:更改现有映射的权限。
msync:冲洗共享映射中的修改页到被映射的文件中。
munmp:解除映射。(对共享映射,文件的更新会根据系统算法更新到文件,对MAP_PRIVATE映射,丢弃修改)
拓展知识
哪些是与磁盘I/O有关的系统调用?参考资料
《unix环境高级编程》ubuntu16.04 man pages
相关文章推荐
- APUE读书笔记-14高级输入输出-02非阻塞IO
- APUE读书笔记-14高级输入输出-06异步IO
- 14(高级IO)
- 14.高级IO
- APUE读书笔记-14高级输入输出-09内存映射IO
- 14、css高级属性
- 高级IO(内存映射等)
- 高级IO之MMAP(一)
- Spark生态之Alluxio学习14--alluxio内存文件加载方式和分布情况分析
- APUE读书笔记-14高级输入输出-01简介
- 高级IO学习总结——异步IO
- APUE读书笔记-14高级输入输出-08readn和writen函数
- IO复用高级应用:同时处理TCP和UDP服务
- linux 高级IO 磁盘映射IO
- 黑马程序员-JAVA高级视频_IO输入与输出-18天-2(FileWriter)
- 黑马程序员-JAVA高级视频_IO输入与输出-18天-5(文本文件读取方式一)
- 黑马程序员-JAVA高级视频_IO输入与输出-19天-11(写入转换流)
- 黑马程序员-JAVA高级视频_IO输入与输出-20天-6(File文件删除)
- Javascript高级程序设计——14.面向对象与原型(2)
- Java学习14 高级I/O编程