Linux文件锁【转】
本文转载自:http://blog.csdn.net/dragon_li_chen/article/details/17147911
一、文件锁的分类:
翻阅参考资料,你会发现文件锁可以进行很多的分类,最常见的主要有读锁与写锁,前者也叫共享锁,后者也叫排斥锁,值得注意的是,多个读锁之间是不会相互干扰的,多个进程可以在同一时刻对同一个文件加读锁;但是,如果已经有一个进程对该文件加了写锁,那么其他进程则不能对该文件加读锁或者写锁,直到这个进程将写锁释放,因此可以总结为:对于同一个文件而言,它可以同时拥有多个读者,但是在某一时刻,他只能拥有一个写者。
根据内核行为来分,文件锁可以分成劝告锁与强制锁两大类:
1. 劝告锁:
劝告锁讲究的是一种协同工作,内核仅负责对文件加锁以及检查文件是否已经上锁等操作,而不亲自去参与文件锁的控制与协调,而这些都需要程序员首先要检查所要访问的文件之前是否已经被其他进程加锁来实现并发控制,劝告锁不仅可以对文件的任一部分加锁,也可以对整个文件加锁。下面是加锁规则:
2.强制锁:
强制锁则是内核强制使用的一种文件锁,每当有进程违反锁规则,内核将会进行阻止,具体的加锁规则如下:
(1)若一个文件已经加上共享锁,那么其他进程在对这个文件进行写操作时将会被内核阻止;
(2)若一个文件已经加上了排他锁,那么其他进程对这个文件的读取与写操作都将被阻止;
下表总结了进程试图访问已经加有强制锁的文件,进程行为如下:
从上表可以看出,若进程要访问文件的锁类型与要进行的操作存在冲突,那么若操作时在阻塞时进行,则进程将会阻塞;若操作时在非阻塞时进程,则进程将会立即返回EAGIN错误(PS:表示资源临时不可达)。
根据加锁区域范围,可以分成整个文件锁与区域文件锁(记录锁),二者很好区分,前者可以锁定整个文件,而后者则可以锁定文件中的某一区域,甚至是某几个字节。
二、文件锁相关的系统调用:
目前跟文件加锁相关的系统调用主要有两个:flock与fcntl, 二者在应用范围方面也存在着一些差别,早起的flock函数只能处理劝告锁,在Linux 2.6版本中将其功能扩充至强制锁,另外flock函数只能对整个文件加锁,不能加记录锁,而fcntl函数则不仅完全支持加劝告锁与强制锁,还支持记录锁,另外因为它符合POSIX标准,具有很好的可移植性。
值得注意的是,在给文件加锁之前,一定要保证文件以相应的访问模式打开,例如要对一个文件加上共享锁,一定要首先按读模式打开文件,若要给文件加上排他锁,则首先要按写模式打开对应文件若想加两种锁,则需要按读写模式打开.
int fcntl(int fd, int cmd, struct flock*lock)
fcntl函数专门用来对文件描述符操作的,具体的操作行为取决于cmd值,与本文文件锁相关的cmd值主要有:
F_GETLK:获取文件锁
F_SETLK:设置文件锁(非阻塞版)
F_SETLKW:设置文件锁(阻塞版)
值得注意的是,调用F_SETLKW命令去设置文件锁的请求不能完成,则进程将会进入休眠状态,直至所要求的锁被释放。其它更多的cmd值可以参考《UNIX环境高级编程》或者”man fcntl”。
lock参数主要是用来实现指定文件锁类型、所锁定的文件范围以及正在锁定文件的进程ID(只是在获取文件锁时才会用到),详细结构如下:
- struct flock {
- short l_type; /* Type of lock: F_RDLCK, F_WRLCK, F_UNLCK */
- short l_whence; /* How to interpret l_start: SEEK_SET, SEEK_CUR, SEEK_END */
- off_t l_start; /* Starting offset for lock */
- off_t l_len; /* Number of bytes to lock */
- pid_t l_pid; /* PID of process blocking our lock (F_GETLK only) */
- };
其中l_type定义所的类型,F_RDLCK表示共享锁,F_WRLCK表示排他锁,F_UNLCK表示释放掉之前已经建立的锁;l_whence, l_start与l_len共同作用设置所加锁的范围,其中l_whence设置锁的参照起始点,SEEK_SET表示文件开头,SEEK_CUR表示文件当前位置(fseek可以移动文件指针位置),SEEK_END表示文件结尾;l_start与l_whence相结合确定了锁的绝对起始点,l_len则表示从绝对起始点开始需要锁定的字节数,其值可正可负,锁的范围则是[l_start, l_start+l_len-1],若其值为0,则有特殊的含义,表示锁的区域从绝对起始点开始到最大可能的偏移量为止,这种情况可用于锁定整个文件,此时只需将锁的绝对起始点设置为文件开始位置即可。
函数的返回值是:若成功则返回0,否则返回-1.
int flock(int fd, int operation)
相对于fcntl函数,flock显得更加简单,因为所加的锁会影响整个文件,其中operation参数规定了所加锁的类型:
LOCK_SH:表示加共享锁
LOCK_EX:表示排他锁
LOCK_UN:表示释放锁
LOCK_MAND:表示强制锁
三、锁的继承与释放:
1. 锁与进程和文件紧密相连,若进程终止,则有它创建的所有锁将会自动释放掉;若关闭文件描述符,则进程由此描述符引用的文件上的任何锁也将会被释放;
2. 由fork产生的子进程不会继承父进程的文件锁;
3. 在执行exec之后,新程序可以继承原来程序的文件锁。
跟锁有关的封装函数(来自于《高级UNIX环境编程》如下测试例子:
- /***************************************file_lock.h*******************************************/
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <string.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <signal.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- int lock_reg(int, int, int, off_t, int, off_t); //register lock
- pid_t lock_test(int, int, off_t, int, off_t); //test lockable
- //set lock
- #define read_lock(fd, offset, whence, len) \
- lock_reg((fd), F_SETLK, F_RDLCK, (offset), (whence), (len))
- #define readw_lock(fd, offset, whence, len) \
- lock_reg((fd), F_SETLKW, F_RDLCK, (offset), (whence), (len))
- #define write_lock(fd, offset, whence, len) \
- lock_reg((fd), F_SETLK, F_WRLCK, (offset), (whence), (len))
- #define writew_lock(fd, offset, whence, len) \
- lock_reg((fd), F_SETLKW, F_WRLCK, (offset), (whence), (len))
- #define un_lock(fd, offset, whence, len) \
- lock_reg((fd), F_SETLK, F_UNLCK, (offset), (whence), (len))
- //Test lock
- #define read_lock_pid(fd, offset, whence, len) \
- lock_test((fd), F_RDLCK, (offset), (whence), (len))
- #define write_lock_pid(fd, offset, whence, len) \
- lock_test((fd), F_WRLCK, (offset), (whence), (len))
- #define is_read_lockable(fd, offset, whence, len) \
- (read_lock_pid == 0)
- #define is_write_lockable(fd, offset, whence, len) \
- (write_lock_pid == 0)
- /******************************************file_lock.c****************************************/
- #include "file_lock.h"
- int lock_reg(int fd, int cmd, int type, off_t offset, int whence, off_t len)
- {
- struct flock lock;
- lock.l_type = type; /* F_RDLCK, F_WRLCK, F_UNLCK */
- lock.l_start = offset; /* byte offset, relative to l_whence */
- lock.l_whence = whence; /* SEEK_SET, SEEK_CUR, SEEK_END */
- lock.l_len = len; /* #bytes (0 means to EOF) */
- return(fcntl(fd, cmd, &lock));
- }
- pid_t lock_test(int fd, int type, off_t offset, int whence, off_t len)
- {
- struct flock lock;
- lock.l_type = type; /* F_RDLCK or F_WRLCK */
- lock.l_start = offset; /* byte offset, relative to l_whence */
- lock.l_whence = whence; /* SEEK_SET, SEEK_CUR, SEEK_END */
- lock.l_len = len; /* #bytes (0 means to EOF) */
- if (fcntl(fd, F_GETLK, &lock) < 0)
- {
- printf("fcntl error for %s.\n", strerror(errno));
- return (-1);
- }
- if (lock.l_type == F_UNLCK)
- {
- return(0); /* false, region isn't locked by another proc */
- }
- return(lock.l_pid); /* true, return pid of lock owner */
- }
- /*****************************************file_lock.c*****************************************/
- #include "file_lock.h"
- static void lock_set(int fd, int type) ;
- int main(int argc, char **argv)
- {
- int fd ;
- //First open file and choose right mode by lock type
- fd = open("/tmp/hello", O_RDWR | O_CREAT, 0666) ;
- if (fd < 0)
- {
- printf("open error ! \n") ;
- exit(1) ;
- }
- //lock
- printf("press ENTER to add lock:\n");
- getchar() ;
- lock_set(fd, F_WRLCK) ;
- printf("press ENTER and exit, lock release:\n");
- getchar() ;
- //release lock
- lock_set(fd, F_UNLCK) ; //useless code, lock release if close fd
- if (close(fd) < 0)
- {
- printf("\n close file error ! \n") ;
- exit(1) ;
- }
- return 0 ;
- }
- void lock_set(int fd, int type)
- {
- pid_t read_lock_id = 0;
- pid_t write_lock_id = 0;
- while (1)
- {
- //set lock according to lock type
- switch (type)
- {
- case F_RDLCK:
- if (read_lock(fd, 0, SEEK_SET, 0) == 0)
- {
- printf("read lock set by %d \n", getpid());
- return;
- }
- break;
- case F_WRLCK:
- if (write_lock(fd, 0, SEEK_SET, 0) == 0)
- {
- printf("write lock set by %d \n", getpid());
- return;
- }
- break;
- case F_UNLCK:
- if (un_lock(fd, 0, SEEK_SET, 0) == 0)
- {
- printf("release lock by %d \n", getpid());
- return;
- }
- break;
- }
- //test lock owner
- if (type == F_RDLCK)
- {
- if ((read_lock_id = read_lock_pid(fd, 0, SEEK_SET, 0)) != 0)
- {
- printf("read lock already set by %d \n", read_lock_id);
- }
- }
- else if (type == F_WRLCK)
- {
- if ((write_lock_id = read_lock_pid(fd, 0, SEEK_SET, 0)) != 0)
- {
- printf("write lock already set by %d \n", write_lock_id);
- }
- }
- }
- }
- /****************************************Makefile*********************************************/
- all: file_lock_test
- CC = gcc
- file_lock_test:
- $(CC) file_syn.c file_lock.c -o file_lock_test
- clean:
- rm -rf *.o file_lock_test
Linux文件锁【转】的更多相关文章
- Linux文件锁flock
Linux文件锁flock 在多个进程同时操作同一份文件的过程中,很容易导致文件中的数据混乱,需要锁操作来保证数据的完整性,这里介绍的针对文件的锁,称之为“文件锁”-flock. flock,建议性锁 ...
- linux文件锁flock【转】
转自: https://www.cnblogs.com/kex1n/p/7100107.html linux文件锁flock 在多个进程同时操作同一份文件的过程中,很容易导致文件中的数据混乱,需要 ...
- Linux 文件锁
当多个进程同时访问操作同一个文件时,我们怎么保证文件数据的正确性. linux通常采用的方法是文件上锁,来避免共享资源的产生竞争状态. 文件锁包括建议性锁和强制性的锁: 建议性的锁 :顾名思义,相对温 ...
- 每天进步一点点——Linux文件锁编程flock
转载请注明出处:http://blog.csdn.net/cywosp/article/details/30083015 1. 场景概述 在多线程开发中.相互排斥锁能够用于对临界资源的保护,防 ...
- Linux文件锁学习-flock, lockf, fcntl
参考 linux中fcntl().lockf.flock的区别 这三个函数的作用都是给文件加锁,那它们有什么区别呢? 首先flock和fcntl是系统调用,而lockf是库函数.lockf实际上是f ...
- linux文件锁的应用,POSIX,unix标准,linux标准
1. perl,flock加锁.java也能加锁. 2. 先创建文件并打开,才能加锁(写打开?). 3. 可以用于判断进程是否一直在运行(用另一进程判断),如果锁一直在,则进程在:锁不在,则原进程或意 ...
- linux 文件锁flock,lockf,fcntl
1.flock,lockf,fcntl之间区别 先上结论:flock是文件锁,锁的粒度是整个文件,就是说如果一个进程对一个文件加了LOCK_EX类型的锁,别的进程是不能对这个文件加锁的. lockf是 ...
- linux文件锁
http://blog.chinaunix.net/uid-25324849-id-3077304.html 在SHELL中实现文件锁,有两种简单的方式.(1)一是利用普通文件,在脚本启动时检查特定文 ...
- Linux文件锁flock ,检测进程是否已经存在
在多个进程同时操作同一份文件的过程中,很容易导致文件中的数据混乱,需要锁操作来保证数据的完整性,这里介绍的针对文件的锁,称之为“文件锁”-flock. 头文件:#include<sys/fil ...
随机推荐
- ajax 为 select 赋值
html 页面<tr> <td class="dc-form-left">权限组:</td> <td class="dc-for ...
- Java学习之for循环打印菱形练习
for循环语句是Java程序设计中非常有用的循环语句.一个for循环可以用来重复执行某条语句,直到某个条件得到满足.在Java 5新增的加强的foreach语法,也非常有用. 1. for语句 for ...
- Oracle中的特殊判式
Oracle中的特殊判式 除了逻辑运算之外,Oracle提供了一些特殊判式.这些判式可以用来生成更加复杂和灵活的查询条件.本节将着重介绍以下几种判式. Between: 取值范围 In: 集合成员测试 ...
- php对象(继承,多态)
/2.继承//function abc(){// $arr = func_get_args();//}//子类只能有一个父类 一个父类 可以有多个子类//override 重写//overlood 重 ...
- 【Kubernetes】kube-dns 持续重启
kuberbetes部署和启动正常,但是kube-dns持续重启 使用命令 kubectl get pods --all-namespaces 得到结果 从图中可以看出kube-dns-c7d8589 ...
- oracle导出多CSV文件的靠谱的
oracle导出多CSV文件的问题 ---------------------------------------------------------------------- 用ksh脚本从orac ...
- codeforces 1041 c 乱搞
#include <bits/stdc++.h> using namespace std; struct po { int val; int id; }; po a[]; vector&l ...
- mysql 统计数据,按照日期分组,把没有数据的日期也展示出来
因为业务需求,要统计每天的新增用户并且要用折线图的方式展示. 如果其中有一天没有新增用户的话,这一天就是空缺的,在绘制折线图的时候是不允许的,所有要求把没有数据的日期也要在图表显示. 查询2019-0 ...
- 每日一个linux命令(1)
ls命令: 1. ls -l -R /home/文件夹 列出/home/文件夹下所有文件和目录的详细资料 2. ls -l t* ...
- Spring + RMI
服务端: RmiServer.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns= ...