分类: LINUX
2012-07-07 22:45:37
1、锁文件
许多应用程序只需要能够针对某个资源创建一个锁文件,然后其他程序通过检查这个文件来判断它们是否被允许访问这个资源。创建锁文件使用fcntl.h头文件(楼主机器上位于/usr/include下)定义的open系统调用,并带上O_CREAT和O_EXCL标志。这样就以原子操作完成两项工作:确定文件不存在,然后创建
点击(此处)折叠或打开
不过在第二次运行以上程序的时候,会提示错误:open failed with error 17(文件已存在,错误码在/usr/include/asm-generic/error-base.h),如果想让程序再次执行成功,就必须删除那个锁文件。在c语言调用中,我们可以使用unlink函数(定义于/usr/include/unistd.h)。另外,以上的代码也不是很合理的,只有open没有close,正常情况下,应该加上以下两行:
(void)unlink( "/tmp/LCK.test");
int unlink (__const char *__name)
点击(此处)折叠或打开
关于unlink的使用,可以参考《unix环境高级编程》第17章,17.3.2唯一链接,在listen前,先unlink以防文件已经存在,accept后再unlink,防止下次调用处问题。曾经楼主在ACE的unix域套接字ACE_LSOCK上遇到address in use,其实就是锁文件已存在没有删除的问题。
2、区域锁定
区域锁定出现,是因为锁文件方式并不适用于访问大型的共享文件。如果一个大文件,由一个程序写入数据,但却由不同的程序同时对这个文件进行更新。处理程序不能等待记录程序结束,所以需要一些协调方法来提供对同一个文件的并发访问。linux提供了2种方法来实现:一是fcntl系统调用和lockf调用。fcntl是最常用的接口,lockf和fcntl非常相似,它一般作为fcntl的备选接口,但是,fcntl和lockf的锁定机制不能同时工作,这是因为,它们使用不同的底层实现,因此绝不要混合使用这两种类型的调用,应该坚持使用其中的一种。
#include
int fcntl(int fildes,int command,...);
fcntl对一个打开的文件描述符进行操作,并能根据command参数的设置完成不同的任务。有三个用于文件锁定的命令选项:
*F_GETLK:用于获取fildes打开的文件的锁信息,不会尝试去锁文件。
*F_SETLK:这个命令对fildes指定的文件的某个区域枷锁或解锁。
*F_SETLKW:与F_SETLK命令作用相同,但在无法获取锁时,这个调用将等待直到可以为止,一旦这个调用开始等待,只有在可以获取锁或收到一个信号时才会返回。
command是要和flock结构配合使用的。
程序对某个文件拥有的所有锁都将在相应的文件描述符被关闭时自动清除,在程序结束时也会自动清除各种锁。
当使用这三个选项时,第三个参数必须是一个指向flock结构的指针,实际的函数原型:
int fcntl(iint fildes,int command,struct flock *flock_structure);
3.锁定状态下的读写操作
当对文件区域枷锁之后,必须使用底层的read和write调用来访问文件中的数据,而不要使用更高级的fread和fwrite,这是因为fread和fwrite会对读写的数据进行缓存,所以执行一次fread调用来读取文件中的头100个字节可能会读取超过100个字节的数据,并将多余的数据在函数库中进行缓存。如果程序再次使用fread来读取下100个字符的数据,它实际上将读取已缓冲在函数库中的数据,而不会引发一个底层的read调用来从文件中读取更多的数据。
一个使用fcntl锁定文件的例子如下:
F_GETLK、F_SETLK、F_SETLKW,l_type提供的选项有F_RDLCK、F_UNLCK、F_WRLCK,分别为读锁,解锁,写锁
测试锁的程序如下: