fcntl函数的说明与实例 (文件加锁)
fcntl函数的说明与实例 (文件加锁)
发布时间:2016-12-27 来源:查字典编辑
摘要:对文件加锁是原子性的,可以用于进程间文件操作的同步。在linux下,有三个函数可以对文件进程加锁,分别是fcntl、flock、lockf。...

对文件加锁是原子性的,可以用于进程间文件操作的同步。在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></p> <p>int fcntl(int fd, int cmd,struct flock *plock );</p> <p>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 */</p> <p>#include <unistd.h>

#include <fcntl.h>

#include <sys/types.h>

#include <sys/stat.h></p> <p>int main()

{

struct flock _lock;</p> <p> _lock.l_type = F_WRLCK;

_lock.l_whence = SEEK_SET;

_lock.l_start = 0;

_lock.l_len = 0;</p> <p> 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;

}</p> <p> int ret = fcntl( fd,F_SETLK,&_lock );

if ( ret < 0 )

{

puts( "fcntl error" );

close( fd );

return 0;

}</p> <p> 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;</p> <p> ret = fcntl( fd,F_SETLK,&_lock );

if ( ret < 0 )

{

puts( "unlock error" );

}</p> <p> close( fd );

}

/* glock.c*/</p> <p>#include <unistd.h>

#include <fcntl.h>

#include <sys/types.h>

#include <sys/stat.h>

#include <stdio.h></p> <p>int main()

{

struct flock _lock;</p> <p> _lock.l_type = F_RDLCK;

_lock.l_whence = SEEK_SET;

_lock.l_start = 0;

_lock.l_len = 0;</p> <p> int fd = open( "/dev/shm/test",O_RDWR );

if ( fd < 0 )

{

perror( "open error" );

return 0;

}</p> <p> int ret = fcntl( fd,F_GETLK,&_lock );

if ( ret < 0 )

{

perror( "fcntl error:" );

close( fd );

return 0;

}</p> <p> printf( "lock is %dn",_lock.l_type );</p> <p> close( fd );

}

在上面的代码中,"_lock.l_type = F_RDLCK;"表示给文件上读共享锁,"_lock.l_whence = SEEK_SET;"表示从文件开头开始加锁,"_lock.l_start = 0;"表示偏移l_whence多少字节开始加锁,"_lock.l_len = 0;"表示加锁的字节数,即长度(Specifying 0 for l_len has the specialmeaning: lock all bytes starting at the location specified by l_whenceand l_start through to the end of file, no matter how large the filegrows.)。

在上面的代码中,分别编译为slock、glock。先运行slock再运行glock:

./slock

sleep now ...

./glock

lock is 1

exit...

slock先给文件上写锁,然后glock测试读共享锁是否能加上,测试结果是已存在一个写锁(F_WRLCK,debian下定义为1)。这里需要注意的是F_GETLK是测试锁是否能加上,如果可以,则struct flock中的l_type为F_UNLCK;如果不行,则l_type为文件当前锁的类型,而l_pid为上锁的进程pid。故如果slock上的锁是F_RDLCK,glock测试的锁也是F_RDLCK,这两个锁是兼容的,返回的l_type类型为F_UNLCK。即你不能通过F_GETLK来判断文件是否上锁,只能测试某个锁是否能加上。

上面的是建议性锁,如果要实现强制性锁,则:

To make use of mandatory locks, mandatory locking must be enabled bothon the filesystem that contains the file to be locked, and on the fileitself. Mandatory locking is enabled on a filesystem using the "-o

mand" option to mount(8), or the MS_MANDLOCK flag for mount(2). Mandatory locking is enabled on a file by disabling group execute permission

on the file and enabling the set-group-ID permission bit (see chmod(1)and chmod(2)).

这是说,要实现强制性锁则须将文件所在的文件系统用"-omand"参数来挂载,并且使用chmod函数将文件用户组的x权限去掉。然后用上面同样的代码就可以了。我第一次见这么奇特的函数,实现一个功能并不是通过本身的参数控制,而是系统设置.....幸好我也不用强制性锁。

以上是fcntl加文件锁的简单例子。需要注意的是不同系统的实现并不一样,宏定义也不一样。如:

http://www.opensource.apple.com/source/xnu/xnu-1456.1.26/bsd/sys/fcntl.h

/* record locking flags (F_GETLK, F_SETLK, F_SETLKW) */

#define F_RDLCK 1 /* shared or read lock */

#define F_UNLCK 2 /* unlock */

#define F_WRLCK 3 /* exclusive or write lock */

而在debian中,/usr/include/bits/fcntl.h

/* For posix fcntl() and `l_type' field of a `struct flock' for lockf(). */

#define F_RDLCK 0 /* Read lock. */

#define F_WRLCK 1 /* Write lock. */

#define F_UNLCK 2 /* Remove lock. */

推荐文章
猜你喜欢
附近的人在看
推荐阅读
拓展阅读
相关阅读
网友关注
最新unix linux学习
热门unix linux学习
操作系统子分类