unix及linux文件锁
有三种不同的文件锁,这三种都是“咨询性”的,也就是说它们依靠程序之间的
合作,所以一个项目中的所有程序封锁政策的一致是非常重要的,当你的程序需
要和第三方软件共享文件时应该格外地小心。
有
些程序利用诸如 FIlENAME.lock
的文件锁文件,然后简单地测试此类文件是否存在。这种方法显然不太好,因为当产生文件的进程被杀后,锁文件依然存在,这样文件也许会被永久锁住。UUCP
中把产生文件的进程号PID存入文件,但这样做仍然不保险,因为PID的利用是回收型的。
这里是三个文件锁函数:
flock();
lockf();
fcntl();
flock()是从BSD中衍生出来的,但目前在大多数UNIX系统上都能找到,在单个主
机上flock()简单有效,但它不能在NFS上工作。Perl中也有一个有点让人迷惑的
flock()函数,但却是在perl内部实现的。
fcntl()是唯一的符合POSIX标准的文件锁实现,所以也是唯一可移植的。它也同
时是最强大的文件锁--也是最难用的。在NFS文件系统上,fcntl()请求会被递
交给叫rpc.lockd的守护进程,然后由它负责和主机端的lockd对话,和flock()
不同,fcntl()可以实现记录层上的封锁。
lockf()只是一个简化了的fcntl()文件锁接口。
无论你使用哪一种文件锁,请一定记住在锁生效之前用sync来更新你所有的文件
输入/输出。
代码示例1
1 lock(fd); 2 write_to(some_function_of(fd)); 3 flush_output_to(fd); /* 在去锁之前一定要冲洗输出 */ 4 unlock(fd); 5 do_something_else; /* 也许另外一个进程会更新它 */ 6 lock(fd); 7 seek(fd, somewhere); /* 因为原来的文件指针已不安全 */ 8 do_something_with(fd); ... 9 一些有用的fcntl()封锁方法(为了简洁略去错误处理): 10 #include <fcntl.h>; 11 #include <unistd.h>; 12 13 read_lock(int fd) /* 整个文件上的一个共享的文件锁 */ 14 { 15 fcntl(fd, F_SETLKW, file_lock(F_RDLCK, SEEK_SET)); 16 } 17 18 write_lock(int fd) /* 整个文件上的一个排外文件锁 */ 19 { 20 fcntl(fd, F_SETLKW, file_lock(F_WRLCK, SEEK_SET)); 21 } 22 23 append_lock(int fd) /* 一个封锁文件结尾的锁, 24 其他进程可以访问现有内容 */ 25 { 26 fcntl(fd, F_SETLKW, file_lock(F_WRLCK, SEEK_END)); 27 } 28 前面所用的file_lock函数如下: 29 struct flock* file_lock(short type, short whence) 30 { 31 static struct flock ret ; 32 ret.l_type = type ; 33 ret.l_start = 0 ; 34 ret.l_whence = whence ; 35 ret.l_len = 0 ; 36 ret.l_pid = getpid() ; 37 return &ret ; 38 }
代码示例2
1 //lock.c 2 #include <stdio.h> 3 #include <unistd.h> 4 #include <fcntl.h> 5 #include <string.h> 6 struct flock* file_lock(short type, short whence) 7 { 8 static struct flock ret; 9 ret.l_type = type ; 10 ret.l_start = 0; 11 ret.l_whence = whence; 12 ret.l_len = 0; 13 ret.l_pid = getpid(); 14 return &ret; 15 } 16 int main() 17 { 18 int fd = open("1.txt", O_WRONLY|O_APPEND); 19 for(int i=0; i<1000; ++i) { 20 fcntl(fd, F_SETLKW, file_lock(F_WRLCK, SEEK_SET)); 21 char buf[1024] = {0}; 22 sprintf(buf, "hello world %d/n", i); 23 int len = strlen(buf); 24 write(fd, buf, len); 25 fcntl(fd, F_SETLKW, file_lock(F_UNLCK, SEEK_SET)); 26 sleep(1); 27 } 28 close(fd); 29 } 30 //lock2.c...同lock.c相比只是修改了下buf内容 31 #include <stdio.h> 32 #include <unistd.h> 33 #include <fcntl.h> 34 #include <string.h> 35 struct flock* file_lock(short type, short whence) 36 { 37 static struct flock ret; 38 ret.l_type = type ; 39 ret.l_start = 0; 40 ret.l_whence = whence; 41 ret.l_len = 0; 42 ret.l_pid = getpid(); 43 return &ret; 44 } 45 int main() 46 { 47 int fd = open("1.txt", O_WRONLY|O_APPEND); 48 for(int i=0; i<1000; ++i) { 49 fcntl(fd, F_SETLKW, file_lock(F_WRLCK, SEEK_SET)); 50 char buf[1024] = {0}; 51 sprintf(buf, "china %d/n", i); 52 int len = strlen(buf); 53 write(fd, buf, len); 54 fcntl(fd, F_SETLKW, file_lock(F_UNLCK, SEEK_SET)); 55 sleep(1); 56 } 57 close(fd); 58 } 59 60 g++ lock.c -o 1 61 g++ lock2.c -o 2 62 执行两个程序就能看到互斥的效果了