http://blog.chinaunix.net/uid-23634108-id-2393492.html
下面介绍两种两种Linux下对文件加锁的两种方式
一、文件锁
思想:
假设有一个文件A。创建一个加锁文件B,通过不同的进程互斥的访问此加锁文件B达到互斥的访问文件A的目的。
源码如下
#include "stdio.h"
#include
#include
#include
#include
#include
#include
/*
此种方法只能锁整个文件,访问被锁的文件后回直接返回
*/
int main(int argc, char* argv[])
{
int fdB;
FILE* pA;
fdB = open("B.lock", O_CREAT | O_EXCL, 0644);
if (fdB < 0 && errno == EEXIST)
{
// 其实是判断文件B.lock是否已经存在
printf("File A.dat is already locked./n");
return -1;
}
else if (fdB < 0)
{
perror("error");
return -1;
}
//下面进行对文件A.dat的访问
pA = fopen("A.dat", "w");
//...
//...
fclose(pA);
close(fdB);
unlink("B.lock"); // 去掉对加锁文件的引用,删除 "B.lock"
return 0;
}
二、记录锁
第二种方式可以实现只锁文件的某个部分,并且可以灵活的选择是阻塞方式还是立刻返回方式。
记录锁通过系统调用 fcntl来实现
#include
int fcntl(int fd, int command, long arg);
struct flock
{
short l_type; // 锁的类型
short l_whence;// 锁的起始
off_t l_start;// 锁的起始偏移,与l_whence相关
off_t l_len; // 锁住多少字节
off_t l_pid; // 拥有锁的进程pid
}
调用fcntl进行加锁的操作时,arg是指向结构体flock的指针。
l_type表示加锁的类型,它可以是以下值:
F_RDLCK 读锁(共享锁)
F_WRLCK 写锁(独占锁)
F_UNLCK 释放锁
参数l_whence和l_start表示锁的起始地址,含义与lseek中的同名参数相同。
l_whence为以下三个值之一:
SEEK_SET: 从文件开始计算
SEEK_CUR: 从当前计算
SEEK_END:从文件末尾计算
参数
l_len表示锁的长度是多少字节,如果为0.表示锁一直延伸到文件按的末尾。
l_pid: 仅在查询锁的时候才用,它是这个锁的拥有者的进程pid
fcntl有三个命令和加锁有关,操作通过参数command来传递,它可以是以下的三个值之一:
F_SETLK: 按照arg进行加锁和解锁的处理,如果因为冲突不能上锁,立刻返回并且errno被设置为EAGAIN。
如果l_type是F_UNLCK,已存在的锁被释放。
F_SETLKW:相当于阻塞式的F_SETLK(W的含义是wait)。如果要上锁的区域被其他进程锁住,使申请不能马上成功,则进入睡眠,
等待原来的锁被释放,在上锁成功后返回,如果在进程阻塞时有信号发生,返回并且errno被设为EAGAIN
F_GETLK:检查是否可以申请由arg决定的锁。如果不和别的进程已经存在的锁发生冲突,arg指向的结构flock中的l_type被赋为
F_UNLCK,其余的成员不变。如果不能给与锁,l_pid被赋为发生冲突的进程的pid。这两种情况下函数都返回0。
下面是一些关于记录锁的规则:
1)锁可以延伸到文件按目前的结尾之后,但是不能扩展到文件头之前,也不能从文件头之前开始。
2)如果l_len为0,锁得到最大长度的延伸,这是我们可以从文件的任何地方开始,向后锁住所有的文件数据,并锁住以后添加到
文件末尾的数据,不管添加多少数据。
3)要锁住整个文件,设l_start为0,l_whence为SEEK_SET,l_len为0。
4)如果一块区域被一个进程加了读锁,则另外的进程可以再给它加上读锁,但是不能加写锁。(共享锁)。
如果一块区域被一个进程加了些锁,则它不能为另外的进程加上读锁或写锁(独占锁)。
5)锁的释放:
当进程终止时,它所有的锁都会被释放(不同与文件锁)。
当文件描述符关闭时,在这个进程中,加在该文件描述符上的所有锁被释放。
一下是示例代码:
#include "stdio.h"
#include
#include
#include
#include
#include
#include
int main(int argc, char* argv[])
{
char cmdStr[128];
int fd = 0;
struct flock lockinfo;
lockinfo.l_type = F_WRLCK;
lockinfo.l_whence = SEEK_SET;
lockinfo.l_start = 0;
lockinfo.l_len = 0;
fd = open("Data.dat", O_CREAT | O_RDWR | O_APPEND, 0666);
if (fd < 0)
{
return 0;
}
// 文件加锁(阻塞式)
fcntl(fd, F_SETLKW, &lockinfo);
// 写文件
strcpy(cmdStr, "wu di zui ji mo./n");
write(fd, (void*)cmdStr, strlen(cmdStr));
printf("HAHA/n");
sleep(10);
close(fd);// 释放记录锁
return 1;
}