unix下3中对文件加锁的函数:
lockf:适用于freeBSD系统
flock:适用于linux系统
fcntl:使用标准POIX ,可移植到任何标准系统上
区别:
1.flock只能加全局锁,fcntl可以加全局锁也可以加局部锁。
2.当一个进程用flock给一个文件加锁时,用另一个进程再给这个文件加锁,它会阻塞或者也可以返回加锁失败(可以自己设置)。
3.当一个进程用fcntl给一个文件加锁时,用另一个进程去读或写文件时必须先获取加锁的信息,然后在给这个文件加锁。
3.当给一个文件加fcntl的独占锁后,再给这个文件加flock的独占锁,其会进入阻塞状态。
4.当给一个文件加flock的独占锁后,用fcntl去获取这个锁信息获取不到,再用fcntl仍然可以给文件加锁。
linux通常采用的方法是文件上锁,来避免共享资源的产生竞争状态。
文件锁包括建议性锁和强制性的锁。建议性的,顾名思义,相对温柔一些,在对文件进行锁操作时,会检测是否已经有锁存在,并且尊重已有的锁。在一般的情况下,内核和系统都不使用建议锁。强制性的锁是由内核执行的锁,当一个文件被上锁进行写入操作的时候,内核将阻止其他进程对其进行读写操作。采取强制性的锁对性能的影响很大,每次进行读写操作都必须检查是否有锁存在。
--------------------------------------我是分割线------------------------------------------------
#include <unistdh.>
int lockf(fd,cmd,size)
int fd,cmd;
long size;
这个方法对只锁定文件而言是最简单的。
其中fd为文件的handle number ,
cmd 为所要使用lockf的功能指定,
size則是执行这个功能所要影响的范围大小。
cmd 这个参数要代进什么样的数值呢?其实在unistd.h中也已经有以下的定义,使用時只要依照所需代入即可:
#define F_ULOCK 0 /* Unlock a previously locked section */
#define F_LOCK 1 /* lock a section for exclusive use */
#define F_TLOCK 2 /* test and lock a section(non-blocking) */
#define F_TEST 3 /* test section for other process' locks */
其中F_TEST并没有lock的功能,其主要目的只是在测试文件是否正被其它 process
锁住而已,当已经被锁住时,lockf 返回-1,否則返回0 ;
而F_LOCK和F_TLOCK 的功能也是将文件锁住,不同之处在于如果这个文件原先已被其它process 锁上时,F_LOCK会block 住,并等候此文件直至被解除锁定为止,至于F_TLOCK 则并不会将自己 block
住,而会马上返回-1,至于F_TLOCK 等不等于下列程序呢?
while (lockf(fd,F_TEST,0L)==-1) {}
lockf(fd,F_LOCK,0L);
结果当然是不等于了!因为这就必须考虑到critical section等问题了!当然,对于一个单纯的系统而言,F_LOCK便可以达到目的,但对于大系统而言,由于许多难以预测的因素,如果某process 沒有把文件unlock,则使用F_LOCK便将因为等不到文件可以上锁而使整个系统陷入starvation,這是程序审计者必需先考虑清楚的风险!
那么lockf 的最后一个参数size又要如何使用呢?其实size的值指的就是从文件目前的读取位置开始,要往前或往后多少位置做lock或unlock的动作,而假若是要对整个文件做lock或unlock的话,则并不需要特別去量测size大小,只要直接输入0 即可,lockf 便会知道所要影响的范围为整个文件了!
#define FILE_NAME "/tmp/filelock"
#include <stdio.h>
#include <unistd.h>
#include <sys/file.h>
int main(int argc , char *agvv[])
{
int fd;
fd = open(FILE_NAME,O_CREAT|O_RDWR,0666);
if( fd == -1)
return -1;
int ret = flock(fd,LOCK_EX|LOCK_NB);
if(ret == 0)
{
printf("first run!\n");
sleep(10);
}else{
printf("already run!\n");
}
return 0;
}
-------------------------------------------我是分割线------------------------------------------
二.fcntl()函数格式
所需头文件:
#include<sys/types.h>,
#include<unistd.h>,
include<fcntl.h>
函数原型:
int fcntl(int fd , int cmd);
int fcntl(int fd,int cmd,long arg);
int fcntl(int fd,int cmd,struct flock * lock);
函数参数:
fd:文件描述符
cmd:
lock:结构为flock,记录锁的具体状态
struct flock
{
}
Lock结构变量取值:
l_type:F_RDLCK:读取锁(共享锁)
l_start:相对位移量(字节)
l_whence:相对位移量的起点(同lseek的whence):
l_len:加锁区域长度
l_pid是加锁进程的进程id,l_pid不需要指定
返回值 成功返回依赖于cmd的值,若有错误则返回-1,错误原因存于errno.
小技巧:为了锁定整个文件,通常的做法是将l_start设置为0,l_whence设置为SEEK_SET,l_len设置为0
二.fcntl()函数使用实例
/************************************************************************
* 文件名:flock.c
* 文件描述:使用文件锁检测进程中是否唯一实例
* 原 理:每次进程启动的时候,对文件获取文件锁,下一次检测文件锁是否获取到,得不到就直接退出
* 创建人: SJW, 2015年10月08日
* 版本号:1.0
* 修改记录:
************************************************************************/
#define FILE_NAME "/tmp/filelock"
#include <stdio.h>
#include <unistd.h>
#include <sys/file.h>
/*================================================================
* 函 数 :is_single_f
* 参 数1:需要存储文件锁的位置
* 功能描述:对指定位置文件获取文件锁,使用的是建议锁,锁定的是全部文件
* 返 回 值:成功0,失败-1
* 抛出异常:
================================================================*/
int is_single_f(char * process_name)
{
int fd;
fd = open(process_name,O_CREAT|O_RDWR,0666);
if( fd == -1)
return -1;
int ret = flock(fd,LOCK_EX|LOCK_NB);
if(ret == 0)
{
printf("first run!\n");
sleep(10);
return 0;
}else{
printf("already run!\n");
return -1;
}
return 0;
}
/*================================================================
* 函 数 :Lockfile
* 参 数1:需要存储文件锁的位置
* 功能描述:对指定位置文件获取文件锁,使用的是建议锁,锁定的是指定位置字符串
* 返 回 值:成功0,失败-1
* 抛出异常:
================================================================*/
int Lockfile(char * process_name)
{
int fd;
fd = open(FILE_NAME,O_CREAT|O_RDWR,0666);
if( fd == -1)
return -1;
struct flock stLock;
stLock.l_type = F_WRLCK; /* F_RDLCK, F_WRLCK, F_UNLCK */
stLock.l_start = 0; /* byte offset, relative to l_whence */
stLock.l_whence = SEEK_SET; /* SEEK_SET, SEEK_CUR, SEEK_END */
stLock.l_len = 0; /* #bytes (0 means to EOF) */
int ret = (fcntl(fd, F_SETLK, &stLock));
if(ret == 0)
{
printf("first run!\n");
sleep(10);
return 0;
}else
{
printf("already run!\n");
return -1;
}
}
int main(int argc , char *agvv[])
{
//if(!is_single_f(FILE_NAME))
if(!Lockfile(FILE_NAME))
printf("\nsingle ok !\n");
else
printf("\ndoule and quit !\n");
return 0;
}
测试结果:
进程1:
[root@localhost 20151008]# ./flock
first run!
single ok !
进程2:
[root@localhost 20151008]# ./flock
already run!
doule and quit !