fcntl函数加文件锁

  对文件加锁是原子性的,可以用于进程间文件操作的同步。在Linux下,有三个函数可以对文件进程加锁,分别是fcntl、flock、lockf。这里只说fcntl,它的用法也是最复杂的。

  fcntl是file control的缩写。在linux下大部分设备都是文件,所以fcntl的功能也比较多,包括:

Duplicating a file descriptor(复制文件描述符)

File descriptor flags(操作close-on-exec标志)

File status flags(操作文件O_RDONLY , O_WRONLY , O_RDWR , O_APPEND , O_NONBLOCK , O_SYNC和O_ASYNC标识)

Advisory locking(建议性锁)

Mandatory locking(强制性锁)

Managing signals(管理信号)

Leases(租借锁)

File and directory change notification (dnotify)(文件和目录更改消息)

Changing the capacity of a pipe(改变管道大小)

这里只说一下Advisory locking和Mandatory locking。建议性锁是指给文件上锁后,只在文件上设置了一个锁的标识。其他进程在对这个文件进程操作时,可以检测到锁的存在,但这个锁并不能阻止它对这个文件进行操作。这就好比红绿灯,当亮红灯时,告诉你不要过马路,但如果你一定要过,也拦不住你。强制性锁则是当给文件上锁后,当其他进程要对这个文件进程不兼容的操作(如上了读锁,另一个进程要写),则系统内核将阻塞后来的进程直到第一个进程将锁解开。在该功能下,fcntl的函数原型为:

#include <unistd.h>
#include <fcntl.h>

int fcntl(int fd, int cmd,struct flock *plock );

struct flock {
              ...
              short l_type;    /* Type of lock: F_RDLCK,
                                  F_WRLCK, F_UNLCK */
              short l_whence;  /* How to interpret l_start:
                                  SEEK_SET, SEEK_CUR, SEEK_END */
              off_t l_start;  /* Starting offset for lock */
              off_t l_len;    /* Number of bytes to lock */
              pid_t l_pid;    /* PID of process blocking our lock
                                  (F_GETLK only) */
              ...
          };

  Advisory locking共有三个操作,分别是F_GETLK、F_SETLK、F_SETLKW。其中F_GETLK用来测试锁,注意是测试而不是获取锁;F_SETLK用来加锁、解锁;F_SETLKW功能同F_SETLK,只是操作变成阻塞式的。而fcntl可以用过l_whence、l_start、l_len来控制文件上锁的区间。下面分别是上锁、测试锁的代码。

/* slock.c */

#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

int main()
{
    struct flock _lock;

_lock.l_type =  F_WRLCK;
    _lock.l_whence = SEEK_SET;
    _lock.l_start = 0;
    _lock.l_len = 0;

int fd = open( "/dev/shm/test",O_CREAT|O_RDWR,S_IRWXU|S_IRGRP|S_IWGRP|S_IRWXO );
    if ( fd < 0 )
    {
        puts( "open error" );
        return 0;
    }

int ret = fcntl( fd,F_SETLK,&_lock );
    if ( ret < 0 )
    {
        puts( "fcntl error" );
        close( fd );
        return 0;
    }

puts( "sleep now ..." );
    sleep( 100 );
    puts( "exit..." );
   
    _lock.l_type =  F_UNLCK;
    _lock.l_whence = SEEK_SET;
    _lock.l_start = 0;
    _lock.l_len = 0;

ret = fcntl( fd,F_SETLK,&_lock );
    if ( ret < 0 )
    {
        puts( "unlock error" );
    }

close( fd );
}

/* glock.c */

#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>

int main()
{
    struct flock _lock;

_lock.l_type =  F_RDLCK;
    _lock.l_whence = SEEK_SET;
    _lock.l_start = 0;
    _lock.l_len = 0;

int fd = open( "/dev/shm/test",O_RDWR );
    if ( fd < 0 )
    {
        perror( "open error" );
        return 0;
    }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/fa6d0578f7761b506e7836f52ea998ad.html