下面介绍两种两种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; }
以上是我一个字一个字打的,累了。不想多说了。不过以上也基本可以满足编程需求了。