文件锁的使用浅析

2018-04-22  本文已影响0人  guotianqing

概述

在多数unix系统中,当多个进程/线程同时编辑一个文件时,该文件的最后状态取决于最后一个写该文件的进程。

对于有些应用程序,如数据库,各个进程需要保证它正在单独地写一个文件。这时就要用到文件锁。

文件锁(也叫记录锁)的作用是,当一个进程读写文件的某部分时,其他进程就无法修改同一文件区域。

能够实现文件锁的函数主要有2个:flockfcntl

早期的伯克利版本只支持flock,该函数只能对整个文件加锁,不能对文件的一部分加锁。

lockf是在fcntl基础上构造的函数,它提供了一个简化的接口。它们允许对文件中任意字节区域加锁,短至一个字节,长至整个文件。


fcntl函数

#include <fcntl.h>

int fcntl(int fd, int cmd, .../*struct flock *flockptr*/);
#返回值:若成功,返回值依赖于cmd,失败返回-1

cmdF_GETLK, F_SETLK, F_SETLKW中的一个。第三个参数是指向flock结构的指针,flock结构如下:

struct flock {
short l_type;/* one of F_RDLCK, F_WRLCK, F_UNLCK */
short l_whence;/* SEEK_SET, SEEK_CUR, SEEK_END */
off_t l_start;/* offset in bytes, relative to l_whence */
off_t l_end;/* length, in bytes, 0 means lock to EOF */
off_t l_pid;/* returned with F_GETLK */
};

其中,


锁的使用

使用锁的基本规则:

fcntl三种cmd的使用:

注意:用F_GETLK 测试能否创建一把锁,然后用F_SETLK尝试建立锁之间并非原子操作,也就是说两次调用之间有可能另一进程插入并创建了相同的锁。如果不希望在等待锁变为可用时产生阻塞,就必须处理由F_SETLK返回的可能出错值

下面是测试一把锁的例子:

#include <stdio.h>
#include <errno.h>
#include <pthread.h>
#include <fcntl.h>

pid_t lock_test(int fd, int type, off_t offset, int whence, off_t len)
{
    struct flock lock;
    
    lock.l_type = type;
    lock.l_start = offset;
    lock.l_whence = whence;
    l   ock.l_len = len;
    
    if (fcntl(fd, F_GETLK, &lock) < 0) {
        printf("fcntl error: %s\n", strerror(errno));
        return 1;
    }
    
    if (lock.l_type == F_UNLCK) {
        return 0;
    }
    
    return lock.l_pid;
}

锁的继承与释放

锁的继承和释放有以下三条原则:

避免死锁

如果两个进程互相等待对方持有并且不释放的资源时,这两个进程就会进入死锁状态。

如果一个进程已经控制了文件中的一个加锁区域,然后它又试图对另一个进程控制的区域加锁,那么它就会进入睡眠,并有可能发生死锁。

检测到死锁时,内核必须选择一个进程接收错误返回。


总结

在多进程或多线程环境中,当多个应用需要读写同一个文件时,需要考虑对文件加锁,以保证对文件修改的一致性。

在使用文件锁时,应明确应用模式,防止死锁。

更多关于文件锁的使用细节,请参考《UNIX环境高级编程》。

上一篇 下一篇

猜你喜欢

热点阅读