1、非阻塞I/O。
不会永远阻塞的I/O操作。
对于一个给定的文件描述符,有两种方法指定非阻塞I/O
①调用open指定O_NONBLOCK标志。
②对已经打开的描述符,调用fcntl,修改一打开文件描述符的O_NONBLOCK标志。
2、记录锁。
record locking
当第一个进程正在读或修改文件的某个部分时,使用记录锁可以阻止其他进程修改同一文件区。(字节范围锁)
apue.h
请求和释放一把锁
int lock_reg(int,int, int, off_t, int, off_t);
#define read_lock(fd,offset, whence, len) \
lock_reg((fd),F_SETLK, F_RDLCK, (offset), (whence), (len))
#define readw_lock(fd,offset, whence, len) \
lock_reg((fd),F_SETLKW, F_RDLCK, (offset), (whence), (len))
#define write_lock(fd,offset, whence, len) \
lock_reg((fd),F_SETLK, F_WRLCK, (offset), (whence), (len))
#define writew_lock(fd,offset, whence, len) \
lock_reg((fd),F_SETLKW, F_WRLCK, (offset), (whence), (len))
#define un_lock(fd,offset, whence, len) \
lock_reg((fd),F_SETLK, F_UNLCK, (offset), (whence), (len))
测试一把锁
pid_t lock_test(int,int, off_t, int,off_t);
#define is_read_lockable(fd,offset, whence, len) \
(lock_test((fd),F_RDLCK, (offset), (whence), (len)) == 0)
#define is_write_lockable(fd,offset, whence, len) \
(lock_test((fd),F_WRLCK, (offset), (whence), (len)) == 0)
记录锁的自动继承和释放3条规则:
² 锁与进程和文件两者相关联
² 有fork产生的子进程不继承父进程所设置的锁
² 在执行exec后,新程序可以继承原执行程序的锁
在文件尾端加锁
Writew_lock(fd,o,SEEK_END,O);
Write(fd,buf,1);
Unclock(fd,o,SEEK_END);
Write(fd,buf,1);
建议性锁:
强制性锁:让内核检查每一个open、read、write,验证调用进程是否违背了正在访问的文件上的某一把锁。
一般的Unix系统文本编辑器并不使用记录锁。(该文件的最后结果取决于写该文件的最后一个进程)
3、死锁
(1)条件:要有一个或多个线程、一个或多个资源,每个线程都在等待其中的一个资源,但所有的资源都已经被占用。所有线程都在互相等待,但他们永远不会释放已经占有的资源。
(2)避免死锁的规则:
4、I/O多路转接
先构造一个我们所关心的描述符列表,然后调用函数(select,pselect,poll)直到这些描述符中的一个已经准备好进行I/O时,该函数才返回。
#include
Int select(int maxfdl,
fd_set *restrict readfds,
fd_set *restrict writefds,
fd_set *restrict exceptfds,
struct timeval *restricttvptr);
5、异步I/O
POSIX异步I/O接口使用AIO控制块来描述I/O操作。
Struct aiocb
{
…
}
6、函数readv 和 writev
用于在一次函数调用中读、写多个非连续缓冲区。---散布读、聚集写
#include
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 addressof buffer
Size_tiov_len; //sizeof buffer
}
7、函数readn 和 written
读写指定的N字节数据,并处理返回值可能小于要求值的情况。
#include “apue.h”
Ssize_t readn(int fd, void *buf, size_tnbytes);
Ssize_t writen(int fd, void *buf,size_tnbytes);
8、存储映射I/O
Memory-mapped I/O
将一个磁盘文件映射到存储空间中的一个缓冲区上,当从缓冲区中取数据时,就相当于读文件中的相应字节。与此类似,将数据存入缓冲区时,相应字节就自动写入文件。
#include
告诉内核将一个给定文件映射到一个存储区域中,返回映射区的起始地址。
Void *mmap(void *addr, size_t len, intprot, int flag, int fd, off_t off);
更改现有映射的权限
Int mprotect(void *addr, size_t len, intprot);
将已经修改的页“冲洗”到被影射的文件中。
Int msync(void *addr, size_t len, intflags);
解除存储映射区的映射
Int munmap(void *addr, size_tlen);