对文件加锁是原子性的,可以用于进程间文件操作的同步。在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的函数原型为:
advisory locking共有三个操作,分别是f_getlk、f_setlk、f_setlkw。其中f_getlk用来测试锁,注意是测试而不是获取锁;f_setlk用来加锁、解锁;f_setlkw功能同f_setlk,只是操作变成阻塞式的。而fcntl可以用过l_whence、l_start、l_len来控制文件上锁的区间。下面分别是上锁、测试锁的代码。
在上面的代码中,"_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 special meaning: lock all bytes starting at the location specified by l_whence and l_start through to the end of file, no matter how large the file grows.)。
在上面的代码中,分别编译为slock、glock。先运行slock再运行glock:
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来判断文件是否上锁,只能测试某个锁是否能加上。
上面的是建议性锁,如果要实现强制性锁,则:
这是说,要实现强制性锁则须将文件所在的文件系统用"-o mand"参数来挂载,并且使用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. */
如对本文有疑问, 点击进行留言回复!!
linux下文本编辑器vim的使用方法(复制、粘贴、替换、行号、撤销、多文件操作)
网友评论