文件I/O和记录锁

2019-05-08  本文已影响0人  食梦狸猫

文件描述符:

文件描述符是一个非负整数,所有打开的文件都通过文件描述符引用。
按照惯例:0(STDIN_FILENO)与进程的标准输入关联,1(STDOUT_FILENO)与标准输出关联,2(STDERR_FILENO)与标准错误输出关联。

文件偏移量

每个打开的文件都有一个与其关联的“当前文件偏移量”,用以度量从文件开始处计算的字节数。当打开一个文件时,除非指定O_APPEND,否则偏移量设置为0。lseek仅将当前的文件偏移量记录在内核中,不引起任何I/O操作,然后偏移量用于下一次读或者写。

空洞

文件偏移量大于文件的长度,在下一次对该文件的写中将加长该文件,并在文件中构成一个空洞。位于文件中没有写过的字节都为0

原子操作

任何一个需要多个函数调用的操作都不是原子操作,因为在多个函数调用之间,内核可能会临时挂起进程,这时若有其他的进程对同一个文件进行操作就会造成不可预知的后果。
原子操作:是由多步组成的操作,要么执行完全部的步骤,要么一步都不执行。
unix系统提供的原子操作:

ssize_t pread(int fileds, void* buf, size_t nbytes,off_t offset);

size_t pwrite(int fileds, const void* buf, size_t bytes, off_t offset);

sync,fsync,fdatasync

延迟写减少了磁盘读写次数,但也降低了内容跟新速度。当系统发生故障时,延迟写可能会造成文件更新内容的丢失。

为了保证文件系统和缓冲区中内容的一致性:

记录锁

若有时两个进程一起同时编辑某个文件,那么文件的状态将取决于写该文件的最后一个进程。

fcntl记录锁

int fcntl(int fd, int cmd, ....);
....

struct flock
{
  short l_type;
//锁类型:F_RDLCK(共享读锁),F_WRLCK(独占写锁),F_UNLCK(解锁一个区域)
  off_t l_start;
  short l_whence;
//加锁或者解锁区域的起始字节偏移量
  off_t l_len;
//区域字节长度,若为0,则表示锁的区域从其起点开始直到最大可能偏移量为止
  pid_t l_pid;
//持有进程的ID
}

//为了锁整个文件,可以设置l_start和l_whence,使锁的起点在文件起始处,并且l_len为0。

共享读锁:多个进程在一个给定的字节上可以有一把共享的读锁。

独占写锁:在一个给定字节上只能由一个进程独占的一把写锁。

如果在一个给定字节上已经有一把或者多把读锁,则不能在该字节上再加写锁。

如果在一个字节上已经有一把独占性的写锁,则不能再加任何读锁。

加读锁时,文件描述符必须读打开。
加写锁时,文件描述符必须写打开。

fcntl函数的三个命令:

死锁

如果两个进程相互等待对方持有并且锁定的资源时,则这两个进程就处于死锁状态。检测到死锁时,内核必须选择一个进程接收出错返回。

锁的隐含继承和释放

守护进程用文件锁加锁,可以保证只有唯一的一个该进程。

int lockfile(int fd)
{
    struct flock f1;

    f1.l_type = F_WRLCK;
    f1.l_start = 0;
    f1.l_whence = SEEK_SET;
    f1.l_len = 0;
    return(fcntl(fd,F_SETLK,&f1));
}

在文件尾端加锁

建议性锁和强制性锁

上一篇 下一篇

猜你喜欢

热点阅读