flock即文件锁,是建议性锁,需要各进程主动去获取与释放。
flock适合进程间通信,不适合用作线程间互斥。
主要应用在解决文件读写冲突上。
linux命令
$ flock -h
Usage:
flock [options] <file|directory> <command> [command args]
flock [options] <file|directory> -c <command>
flock [options] <file descriptor number>
Options:
-s --shared get a shared lock
-x --exclusive get an exclusive lock (default)
-u --unlock remove a lock
-n --nonblock fail rather than wait
-w --timeout <secs> wait for a limited amount of time
-E --conflict-exit-code <number> exit code after conflict or timeout
-o --close close file descriptor before running command
-c --command <command> run a single command string through the shell
-h, --help display this help and exit
-V, --version output version information and exit
For more details see flock(1).
shared lock 共享锁
exclusive lock 排他锁
当文件被上了共享锁之后,其他进程可以继续为此文件加共享锁,但此文件不能被加排他锁,此文件会有一个共享锁计数,加上一个共享锁计数+1,解锁后-1,只有当共享锁计数为0时,才有可能被上排他锁。
当文件被上了排锁之后,在解锁前,不能上共享锁和排他锁。
# 创建一个锁文件,可以是任意文件或文件夹
touch flock.lock
# 在flock.lock文件上加排他锁后,执行休眠30s
flock -x flock.lock -c 'sleep 30' # command 1
# 另起一个终端
flock -s flock.lock -c 'echo hello' # 会在 # <command 1> 执行后30s 输出'hello'
// write_1.cc
#include <sys/file.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
int main(int argc,char* argv[]){
const char* lock_file_path = "flock.lock";
if(argc >= 2){lock_file_path = argv[1];}
int fd = 0;
assert((fd = open(lock_file_path,"r")) > 0); // 使用文件锁之前须要得到锁文件的file desc
assert(0 == flock(fd,LOCK_SH)) // 加上共享锁
char buff[256],str[1024];
bzero(buff,sizeof(buff));
bzero(str,sizeof(str));
size_t rd = 0;
while((rd = read(fd,buff,sizeof(buff)-1)) > 0) {
buff[rd] = '\0';
strcat(str,buff);
}
printf("load str from %s is %s\n",lock_file_path,str);
flock(fd,LOCK_UN) // 解锁
close(fd); // 如果没有多个 file_description 指向同一个文件,那么可以使用close(fd),隐式解锁,但不建议
return 0;
}
// read_1.cc
#include <sys/file.h>
#include <stdio.h>
#include <assert.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
int fd = 0;
void signal_handle(int sig){
switch(sig){
case SIGKILL:
case SIGQUIT:
case SIGINT:
case SIGSTOP:
if(fd){
flock(fd,LOCK_UN);
close(fd);
}
exit(0);
default:
return;
}
}
int main(int argc,char* argv[]){
const char* lock_file_path = "flock.lock";
if(argc >= 2){
lock_file_path = argv[1];
}
assert((fd = open(lock_file_path,"w")) > 0);
signal(SIGKILL,signal_handle);
signal(SIGQUIT,signal_handle);
signale(SIGINT,signal_handle);
while(true){
assert(0 == flock(fd,LOCK_EX)) // 加上排他锁
char *str=nullptr;
size_t str_size = 0;
getline(&str,&str_size,stdin);
write(fd,str,str_size);
assert(0 == flock(fd,LOCK_UN));
sleep(2);
}
return 0;
}
// flock_guard.hpp
#include <string>
#include <sys/file.h>
#include <cassert>
class flock_guard{
int fd;
public:
flock_guard(const std::string& filepath,
int lock_type // LOCK_SH 或 LOCK_EX
){
assert((fd = open(filepath.c_str(),"r")) > 0);
assert(0 == flock(fd,lock_type));
}
virtual ~flock_guard(){
flock(fd,LOCK_UN);
close(fd);
}
};
// 包装读写锁
// read flock guard
class rflock_guard : public flock_guard{
public:
rflock_guard(const std::string& filepath)
:flock_guard(filepath,LOCK_SH) //使用共享锁 作读锁
{}
};
// write flock guard
class wflock_guard:public flock_guard{
public:
wflock_guard(const std::string& filepath)
:flock_guard(filepath,LOCK_EX) // 使用排他锁 作写锁
{}
};