文件锁和记录锁

http://blog.chinaunix.net/uid-23634108-id-2393492.html

 

下面介绍两种两种Linux下对文件加锁的两种方式
一、文件锁
思想:
假设有一个文件A。创建一个加锁文件B,通过不同的进程互斥的访问此加锁文件B达到互斥的访问文件A的目的。
源码如下

#include "stdio.h"
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <mysql/mysql.h>
#include <errno.h>

/*
此种方法只能锁整个文件,访问被锁的文件后回直接返回
*/

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 <fcntl.h>
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 <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <mysql/mysql.h>
#include <errno.h>


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;

}

 

猜你喜欢

转载自blog.csdn.net/iot_shun/article/details/81027130