UNIX环境高级编程——高级I/O
非阻塞I/O
非阻塞I/O使我们可以发出 open、read 和 write 这样的I/O操作,并使这些操作不会永远阻塞。如果这种操作不能完成,则调用立即出错返回,表示该操作如继续执行将阻塞。
对于一个给定的描述符,有两种为其指定非阻塞I/O的方法。
- (1)如果调用 open 获得描述符,则可指定 O_NONBLOCK 标志。
- (2)对已经打开描述符,调用 fcntl 打开O_NONBLOCK文件标志。
非阻塞在I/O,会立即返回;通过返回结果可获知是否正确完成信息。
记录锁
记录锁的功能是:当第一个进程正在读或修改文件的某个部分时,使用记录锁可以阻止其他进程修改同一文件区。
fcntl记录锁
#include <fcntl.h>
int fcntl(
int fd,
// F_GETLK/F_SETLK/F_SETLKW
// cmd为F_GETLK,参数3-flock*是一个值-结果参数
int cmd,
...);
返回值:若成功,依赖于 cmd ,否则,返回-1
struct flock
{
// F_RDLCK/F_WRLCK/F_UNLCK
short l_type;
// SEEK_SET/SEEK_CUR/SEEK_END
short l_whence;
// start offset
off_t l_start;
off_t l_len;
// 返回持有此锁的进程的ID
pid_t l_pid;
};
调用进程已经持有文件A区间A的一个锁后,希望再对文件A区间A加另一个锁,处理方式是直接用新锁替换旧锁(进程对文件A区间A只加一个锁,锁为最后调用fcntl施加的那个)。
锁的隐含继承和释放
关于记录锁的自动继承和释放有3条规则。
- (1)锁与进程和文件两者相关联。
这有两重含义:第一重很明显,当一个进程终止时,它所建立的锁全部释放;第二重则不太明显,无论一个描述符何时关闭,该进程通过这一描述符引用的文件上的任何一把锁都会释放(这些锁都是该进程设置的)。 - (2)由fork产生的子进程不继承父进程所设置的锁。
意味着,若一个进程得到一把锁,然后调用 fork ,那么对于父进程获得的锁而言,子进程被视为另一个进程。
对于通过 fork 从父进程处继承过来的描述符,子进程需要调用 fcntl 才能获得它自己的锁。 - (3)在执行 exec 后,新程序可以继承原执行程序的锁。
注意,如果对于各文件描述符设置了执行时关闭标志,那么当作为 exec 的一部分关闭该文件描述符时,将释放相应文件的所有锁。
FreeBSD
记录锁通过文件+进程来标识。
在父进程中,关闭 fd1,fd2 或 fd3