
前言
1、文件锁包含劝告式锁和强制式锁。
劝告式锁:要求每个使用上锁文件的进程都要检查是否有锁存在,并且尊重已有的锁。在一般情况下,内核和系统都不使用建议性锁,它们依靠程序员遵守这个规定。
强制式锁:是由内核执行的锁,当一个文件被上锁进行写入操作的时候,内核将阻止其他任何文件对其进行读写操作。采用强制性锁对性能的影响很大,每次读写操作都必须检查是否有锁存在。
2、使用文件锁的操作函数有flock()和fcntl()
flock():对整个文件。其中包含共享锁和互斥锁
fcntl():对文件区域或整个文件。其中包含读锁(共享锁)和写锁(互斥锁)
本文使用的内容全为劝告式锁。
一、flock()给文件加锁
头文件:#include <sys/file.h>
int flock(int fd, int operation);
success:0 error:-1
fd:打开文件的描述符
operation:
LOCK_SH:给fd引用的文件加上共享锁
LOCK_EX:给fd引用的文件加上互斥锁
LOCK_UN:解除fd引用的文件
LOCK_NB:非阻塞的请求
eg:
fd1 = open ("test.txt", O_RDWD);
flock (fd1, LOCK_EX);/flock (fd2, LOCK_SH);
①、当一个进程给一个文件加共享锁时,如果另一个进程也给加共享锁这是可以的。如果另外一个进程加的是互斥锁会加锁失败进入阻塞。如果其有OR LOCK_NB则立即返回 -1 errno设为EWOULDBLOCK。
②、当一个进程给一个文件加互斥锁时,另外一个进程不管加共享锁或则互斥锁都会失败进入阻塞。如果其有OR LOCK_NB则立即返回 -1 errno设为EWOULDBLOCK。下表1为总结。
表1:
是否满足请求 | 是否满足请求 | |
---|---|---|
当前加上的锁 | 共享锁 | 互斥锁 |
无 | 是 | 是 |
共享锁 | 是 | 否 |
互斥锁 | 否 | 否 |
二、fcntl()给记录(文件)加锁
头文件:
#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, struct flock *lock);
success:0 error:-1
fd:打开文件的描述符
cmd:
F_GETLK:根据lock参数值,决定是否可以上文件锁
F_SETLK:设置lock参数值的文件锁
lock:是一个指向flock结构的指针,设置记录锁的具体状态
struct flock
{
short l_type; / 锁的类型 /
short l_whence; / 偏移量的起始位置: /
off_t l_start; / 从l_whence的偏移量 /
off_t l_len; / 从l_start开始的字节数 /
pid_t l_pid; / 锁所属进程ID(一般不用) */
}
l_type: F_RDLCK读锁、F_WRLCK写锁、F_UNLCK删除一把既有锁。
l_whence: 有SEEK_SET、SEEK_CUR和SEEK_END
l_len: start后/前的锁定区域长度。为0时表示从起点开始直至最大
可能位置为止。
读锁可一直加,写锁只能有一个,其他会进入阻塞。效果同表1
1、write_lock.c 互斥写
写锁是互斥写。
下面的实例是文件写入锁的测试用例,文件名为,wirte_lock.c 。
这里首先创建了一个hello 文件,之后对其上写入锁,最后释放写入锁,代码如下所示
#include<stdio.h>
#include <unistd.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int lock_set(int fd,int type)
{
struct flock old_lock,lock;
lock.l_whence = SEEK_SET;
lock.l_start = 0;
lock.l_len = 0;
lock.l_type = type;
lock.l_pid = -1;
fcntl(fd,F_GETLK,&lock);
if(lock.l_type != F_UNLCK)
{
if (lock.l_type == F_RDLCK)
{
printf("Read lock already set by %d\n",lock.l_pid);
}
else if (lock.l_type == F_WRLCK)
{
printf("Write lock already set by %d\n",lock.l_pid);
}
}
lock.l_type = type;
if ((fcntl(fd,F_SETLKW,&lock)) < 0)
{
printf("Lock failed : type = %d\n",lock.l_type);
return 1;
}
switch (lock.l_type)
{
case F_RDLCK:
{
printf("Read lock set by %d\n",getpid());
}
break;
case F_WRLCK:
{
printf("write lock set by %d\n",getpid());
}
break;
case F_UNLCK:
{
printf("Release lock by %d\n",getpid());
return 1;
}
break;
default:
break;
}
return 0;
}
int main(void)
{
int fd;/* 首先打开文件*/
fd = open("hello",O_RDWR | O_CREAT, 0644);if(fd < 0)
{
printf("Open file error\n");
exit(1);
}
lock_set(fd, F_WRLCK); /* 给文件上写入锁*/
getchar(); /*程序暂停,按回车键继续*/
lock_set(fd, F_UNLCK); /* 给文件解锁*/
getchar();
close(fd);
exit(0);
return 0;
}
开启两个终端,并且在两个终端上同时运行该程序,以达到多个进程操作一个文件的效果。首先在终端1运行,然后在终端2上运行,注意终端二中的第一行输出。
2、read_lock.c 共享读
读锁是共享读。
接下来的程序是文件读取锁的测试用例,原理和上面的程序一样。只把main函数改成一下内容。文件名为read_lock.c。
int main(void)
{
int fd;fd = open("hello",O_RDWR | O_CREAT, 0644);if(fd < 0)
{
printf("Open file error\n");
exit(1);
}
lock_set(fd, F_RDLCK); /* 给文件上读取锁*/
getchar();
lock_set(fd, F_UNLCK); /* 给文件解锁*/
getchar();
close(fd);
exit(0);
return 0;
}
源码:https://blog.csdn.net/rl529014/article/details/51336161
三、互斥锁与条件变量
四、信号量
五、读写锁
待记录