文件 上锁 flock fcntl

文件上锁

当多个进程试图写同一个文件,将发生什么?它们相互冲突,已知的事情像文件上锁。结果就是每个文件描都有自己的描述符跟偏移量,当每个进程写自己 的文件时,偏移量预先独立导致没有进程知道其他的进程也正在执行写操作。最后的文件将因为多个独立写文件的操作使混合后的文件变得相当于垃圾,直接给文件 上锁是解决这个问题的一种方式。在任意时刻只能让一个进程能够写到文件,另一种办法是允许在一个叫做高级文件锁的scheme里的文件内部进行区域锁 定。 fcntl函数能够提供这个功能,通常来说,锁有两种,一种是写,另一种是读,不同之处在于读锁不会干扰其它进程读取文件,但是特定的区域只能一个 写锁存在。

当使用顾问锁的时候,下面的结构用作fcntl的第三个参数。

  struct flock {

            off_t   l_start;    /* starting offset */
            off_t   l_len;      /* len = 0 means until end of file */
            pid_t   l_pid;      /* lock owner */
            short   l_type;     /* lock type:   */
            short   l_whence;   /* type of l_start */
    };



让我们继续讨论每个元素的细节。

l_start

这是一个相对于l_whence,单位为字节的偏移量,换句话说,要求的位置实际上是l_whence + l_start

l_len

需设置为期望位置的长度,单位为字节,锁将从l_whence + l_start开始锁定l_len字节,如果你想整个文件用一把锁,那么设定l_len的值为0,如果l_len的值是一个负数,结果是不可预测的。

l_pid

需要设置为工作在锁上的进程的ID

l_type

需要设置为期望的锁的类型,下面是能够使用的值

    * F_RDLCK - 读锁定
    * F_WRLCK - 写锁定
    * F_UNLCK - 用作清除锁定

l_whence

这是这个系统调用里面最混乱的部分,这个字段将决定l_start位置的偏移量,需要设为:
    * SEEK_CUR - 在当前位置
    * SEEK_SET - 在文件开始
    * SEEK_END - 在文件末尾

fcntl的命令

下面的可用作fcntl的命令

#define  F_GETLK      7


F_GETLK 命令尝试检查否能上锁,当使用这个命令,fnctl将检查是否有相冲突的锁,如果存在相冲突的锁,fnctl将改写flock结 构,用冲突锁消息通过检查,如果没有相冲突的锁,那么在flock结构最初的信息将被保留,除非l_type字段被设成F_UNLCK

#define  F_SETLK      8


F_SETLK命令试图获得flock结构描述的锁,如果锁不被承认,本次调用将不被阻塞。不管怎样,fcntl将直接返回EAGAIN,同时将设置相应的errno,当flock结构的l_type被设置为F_UNLCK时,你能够使用这个命令清除一个锁。

#define  F_SETLKW     9


F_GETLK命令试图获得flock结构描述的锁,它将命令fnctl阻塞,直到赋予一个锁

5.4为什么用FLOCK  

对大部分情况来说,高级文件锁定机制是有好处的。然而,POSIX.1接口有几个缺点。第一,当一个文件的任何一个文件描述符被关闭时,与该文件 关联的所有锁定必须被删除。换句话说,如果你有一个进程打开一个文件,接着它调用一个函数打开同一个文件,读取然后关闭它,这样先前你对这个文件的所有锁 定都会被删除。如果你并不确定一个库例程会做什么,这将会引起严重问题。第二,锁定是不会传递给子进程的,所以一个子进程必须独立地创建属于它自己的锁 定。第三,所有在一个exec调用之前获得的锁定在由exec启动的进程释放,关闭这个文件或结束之前不会被释放。所以,如果你需要锁定文件的某一部分, 那么调用exec不需要释放锁定或者关闭文件描述符,那部分区域将被锁定直到进程结束,你想要的或许不是预期的结果,不论如何,BSD的设计者用许多 flock创建了非常简单的优先级文件上锁的接口.

flock用于锁定整个文件,是BSD优先选择的方法,跟fcntl高级锁定相反,flock机制允许锁定进入子进程,使用flock调用的其他 好处是可以在文件级并且不在文件描述符级别完成锁定,在某些情况下可用优先选择,意味着多个参照同一个文件的文件描述符,例如DUP()调用,或者多个 OPEN()调用,希望每一个参照相同的文件锁,带flock的文件锁跟一个写多个读的fcntl锁很类似,不论如何,当下面的操作被定义,调用 flock时,锁的优先级能够被提升:

#define   LOCK_SH        0x01      /* shared file lock */


LOCK_SH操作用于在文件上(类似fcntl的读锁)创建共享锁,在一个文件上,多个进程能够共享一把锁。

#define   LOCK_EX        0x02      /* exclusive file lock */


LOCK_EX操作用于在文件上创建互斥锁,当互斥锁生效时,文件上不能存在其他的共享锁,包括已共享的锁。

#define   LOCK_NB        0x04      /* don't block when locking */


使用这个,flock的调用将阻塞,直到锁定生效,不论如何,假如期望的操作LOCK_NB是ORed,flock的调用将向EWOULDBLOCK返回错误号成功(0)或者失败(1).

#define   LOCK_UN        0x08      /* unlock file */


LOCK_UN用于移除文件上的锁

通过调用期望的flock,flock锁的优先级能够被提升或者降低。新的成功的调用将使最近生效的锁替换先前的锁。

posted on 2012-02-16 10:07  Richard.FreeBSD  阅读(767)  评论(0编辑  收藏  举报

导航