当前位置: 首页 > 工具软件 > Flock > 使用案例 >

linux flock简介与简单应用

施凡
2023-12-01

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).
  • 上锁
    文件锁有两种
  1. shared lock 共享锁

  2. exclusive lock 排他锁

    当文件被上了共享锁之后,其他进程可以继续为此文件加共享锁,但此文件不能被加排他锁,此文件会有一个共享锁计数,加上一个共享锁计数+1,解锁后-1,只有当共享锁计数为0时,才有可能被上排他锁。
    当文件被上了排锁之后,在解锁前,不能上共享锁和排他锁。

  • linux命令实践
# 创建一个锁文件,可以是任意文件或文件夹
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'
  • C编程
// 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;
}
  • 简易包装成guard
// 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) // 使用排他锁 作写锁
	{}
};
 类似资料: