《APUE》读书笔记-第十四章高级I/O

1、非阻塞I/O

对低速设备的I/O操作可能会使进程永久阻塞,这类系统调用主要有如下情况:
(1)如果数据并不存在,则读文件可能会使调用者永远阻塞(例如读管道、终端设备和网络设备)。
(2)如果数据不能立即被接受,则写这些同样的文件也会使调用者永远阻塞;
(3)在某些条件发生之前,打开文件会被阻塞(例如以只写方式打开一个FIFO,那么在没有其他进程已用读方式打开该FIFO时);
(4)对已经加上强制性锁的文件进行读、写;
(5)某些ioctl操作;
(6)某些进程间通信函数;

非阻塞I/O调用open、read和write等I/O操作函数使上述的慢速系统调用在不能立即完成的情况下,立即出错返回。

对一个给定的描述符有两种方法设置其为非阻塞:
(1)如果是调用open以获得该描述符,则可指定O_NONBLOCK标志;
(2)对于已经打开的一个描述符,则可调用fcntl打开O_NONBLOCK文件状态标志(注意:设置文件状态标志的方法)。

2、记录锁

  记录锁的功能是:一个进程正在读或修改文件的某个部分时,可以阻止其他进程修改同一文件区。对于UNIX,实际上,由于内核没有“记录”的概念,因此,“记录锁”实际上是“区域锁”。

fcntl记录锁:int fcntl(int fd, int cmd, ……/* struct flock *flockptr */);对于记录锁,cmd是F_GETLK,f_SETLK,或F_SETLKW。第三个参数是一个指向flock结构的指针:

struct flock {
short l_type; /* F_RDLCK, F_WRLCK, or F_UNLCK */
off_t l_start;
short l_whence;
off_t l_len;
pid_t l_pid;
}

   关于加锁和解锁区域需要注意以下几点:该区域可以在当前文件尾端处开始或越过其尾端处开始,但不能在文件起始位置之前或越过该起始位置;若l_len为0,则表示锁的区域从其起点开始,直至最大可能位置为止。

  两种锁:共享读锁(L_RDLCK)和独占写锁(L_WRLCK)的基本规则是,多个进程在一个给定的字节上可以有一把共享的读锁。但是在一个给定字节上的写锁则只能由一个进程独用。加读锁时,该描述符必须是读打开;加写锁时,该描述符必须是写打开的。

不同类型锁之间的兼容性如下:

 

读锁
写锁
无锁
允许
允许
一把或多把读锁
允许
拒绝
一把写锁
拒绝
拒绝
关于记录锁的自动继承和释放有三条规则:
(1)锁与进程、文件两方面有关:第一,当一个进程终止时,它锁建立的锁全部释放;第二,任何时候关闭一个描述符,则该进程通过这一描述符可以访问的文件上的任何一把锁都被释放。
(2)由fork产生的子进程不继承父进程所设置的锁。
(3)在执行exec后,新程序可以继承原执行程序的锁。
3、I/O多路转接
  其基本思想是:先构造一张有关描述符的表,然后调用一个函数,它要到这些描述符中的一个已准备好进行I/O时才返回。在返回时,它告诉进程哪一个描述符已准备好。select、pselect和poll函数能执行I/O多路转接。函数原型如下:
int select(int maxfd, fd_set *readset, fd_set *writeset, fd_set *exceptset, struct timeval *timeout);返回准备就绪的描述符数,超时则为0,出错为-1
参数timeout指定内核等待的时间,其结构如下:
struct timeval {
long tv_sec; /* seconds */
long tv_usec; /* microseconds */
}
传给select的参数告诉内核:我们所关心的描述符;对于每个描述符我们所关心的条件;希望等待多长时间。
从select返回时,内核告诉我们:已准备好的描述符数量;哪一个描述符已准备好读、写或异常条件。
int pselect (int maxfdp1, fd_set *readset, fd_set * writeset, fd_set * exceptset, const struct timespec * timeout, const sigset_t *sigmask);
返回:准备好的描述字个数,0-超时,-1-出错。
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
struct pollfd {
int fd; /* file descriptor */
short events; /* requested events */
short revents; /* returned events */
};
关于I/O多路转接将会在Unix网络编程中详细学习,在本章主要是了解这思想。
 4、异步I/O
  SVR4和4.3+BSD提供了使用一个信号(在SVR4中是SIGPOLL,在4.3+BSD中是SIGIO)的异步I/O方法,该信号通知进程,对某个描述符所关心的某个事件已经发生。异步I/O的一个限制是每个进程只有一个信号。
5、readv和writev函数
头文件:#include
函数原形:     ssize_t readv(int filedes,const struct iovec *iov,int iovcnt);
                 ssize_t writev(int filedes,const struct iovec *iov,int iovcnt);
参数:filedes     文件描述符
         iov         指向iovec结构数组的一个指针。
         iovcnt     数组元素的个数
返回值:若成功则返回已读、写的字节数,若出错则返回-1
struct iovec {
  void *iov_base; /* 起始地址 */
  size_t iov_len; /* 需要传输的字节数 */
};
readv () 系统调用从文件描述符  fd  关联的文件里读取数据到  iovcnt  个由  iov  结果描述的缓存区里。(分散读)

writev() 系统调用把 iovcnt 个由 iov 结构描述的缓存区数据写入文件描述符 fd 关联的文件里。(聚合写)



你可能感兴趣的:(UNIX环境编程)