Linux程序设计:高级文件操作-文件锁

目录

高级文件操作-文件锁

文件锁按功能分为

fcntl函数

flock结构体

加锁和解锁区域的注意

锁的继承与释放

案例一

案例二


高级文件操作-文件锁

  • 当多个用户共同使用、操作一个文件的时候,linux通常采用的方法是给文件上锁,来避免共享资源产生竞争的状态

文件锁按功能分为

共享读锁
  • 文件描述符必须读打开
  • 一个进程上了读锁,其它进程也可以上读锁进行读取
独占写锁
  • 文件描述符必须写打开
  • 一个进程上了写锁,其它进程就不能上写锁和读锁进行读写操作
  • 文件锁按类型分为建议性锁和强制性锁。
    • 建议性锁要求上锁文件的进程都要检测是否有锁存在,并尊重已有的锁。
    • 强制性锁由内核和系统执行的锁。
  • fcntl不仅可以实施建议性锁而且可以实施强制性锁。

fcntl函数

#include <unistd.h>
#include <fcntl.h>
int fcntl(int fd, int cmd, struct flock *lock);
cmd: F_SETLK、F_GETLK 和 F_SETLKW

flock结构体

l_type
  • 锁类型,F_RDLCK(共享读锁)、F_WRLCK(独占性写锁)或F_UNLCK(解锁一个区域)
l_start、l_whence
  • 要加锁或解锁的区域的起始地址,由l_start和l_whence 两者决定
  • l_start是相对位移量,l_whence则决定相对位移量的起点。
l_len
  • 表示区域的长度

加锁和解锁区域的注意

  • 该区域可以在当前文件尾端处开始或越过其尾端处开始,但是不能在文件起始位置之前开始或越过该起始位置。
  • 如若l_len为0,则表示锁的区域从其起点(由l_start和l_whence决定)开始直至最大可能位置为止
    • 也就是不管添写到该文件中多少数据,它都处于锁的范围。
  • 为了锁整个文件,通常的方法是将l_start设为0,l_whence设为SEEK_SET,l_len设为0。

锁的继承与释放

  • 一个进程终止,它所建立的锁全部释放
  • 关闭一个文件描述符,此进程对应该文件的所有的锁均释放。
  • 子进程不继承父进程的锁
  • 执行exec以后,新程序可以选择是否继承原来执行进程的锁。

案例一

  • io.h
#ifndef _IO_H_
#define _IO_H_
#include <sys/types.h>
//...

extern int lock_reg(int fd, int cmd, short type , off_t offset, short whence, off_t length);

#define READ_LOCKW(fd, offset, whence, length) \
		lock_reg(fd, F_SETLKW, F_RDLCK, offset, whence, length)
#define READ_LOCK(fd, offset, whence, length) \
		lock_reg(fd, F_SETLK, F_RDLCK, offset, whence, length)
#define WRITE_LOCKW(fd, offset, whence, length) \
		lock_reg(fd, F_SETLKW, F_WRLCK, offset, whence, length)
#define WRITE_LOCK(fd, offset, whence, length) \
		lock_reg(fd, F_SETLK, F_WRLCK, offset, whence, length)
#define UNLOCK(fd, offset, whence, length) \
		lock_ reg(fd, F_SETLK, F_UNLCK, offset, whence, length)

#endif
  • io.c部分代码
//...
int lock_reg(int fd, int cmd, short type, off_t offset, short whence, off_t length)
{
	struct flock flock;
	flock.l type = type;
	flock.l_start = offset;
	flock.l_whence = whence;
	flock.l_len = length;
	//flock.t_pid = getpid();
	//l_pid:加锁、解锁进程的进程号(pid)
	if(fcntl(fd, cmd, &flock)< 0){
	    perror("fcntl error");
	    return 0;
	}
	return 1;
)
  • 编译
gcc -o obj/io.o -Iinclude -c src/io.c
  • 调用
int main(int argc,char* argv[]){
	if(argc < 4){
		printf("usage:%S content file locktype\n", argv[0]);
		exit(1);
	}
	ssize_t size = strlen(argv[1]) * sizeof(char);
	int fd = open(argv[2],0_WRONLY | 0_CREAT,0777);
	if(fd < 0){
		perror("open error");
		exit(1);
	}
	//第二个进程想要对文件加文件锁(这里是独占写锁)
	//必须要等前一个进程释放了文件锁后方可加锁.
	if(!strcmp("lock", argv[3]))
		WRITE_LOCKW(fd, 0, SEEK_SET, 0);
	printf("lock success\n");
	printf("lock pid:%d\n", getpid());
	sleep(5); 
	if(!strcmp("lock", argv[3]))
		WRITE_LOCKW(fd, 0, SEEK_SET, 0); 
	printf("lock success\n"); 
	printf("lock pid: %d\n", getpid()); 

	char *p = argv[1]; 
	int i; 
	for(i = 0; i < size; i++){
		if (write(fd, (p+i), 1)!= 1){
		perror("write error"); 
		exit(1);
	}
	printf("%d success write one character\n", getpid()); 
	sleep(1); 
	}
	if(!strcmp("unlock", argv[3]))
	    UNLOCK(fd, 0, SEEK_SET, 0);
	printf ("unlock success\n"); 
	printf("unlock pid: %d\n", getpid()); 

	close(fd); 
	return 0;
}
  • 编译
gcc -o bin/lock_write -Iinclude obj/io.o src/lock_write.c
  • 编写start.h脚本文件
bin/lock_write aaaaaa demo.txt Lock &
bin/Lock_write AAAAAA demo.txt lock &
  • 运行结果

  • 改变脚本如下
bin/lock_write aaaaaa demo.txt Lock &
bin/Lock_write AAAAAA demo.txt unlock &
  • 运行结果(第二个进程关闭了文件锁,没有锁时,由于这里的文件锁是建议性锁,所以能继续向文件中输入数据,出现交替输入的情况)

案例二

int main(int argc, char *argv[]){
	if(argc < 4){
		printf("usage: %S content file lock I unlock\n" , argv[0]); 
		exit(1); 
		}
		ssize_ t size = strlen(argv[1]) * sizeof(char); 
		int fd = open(argv[2], 0_ WRONLY| 0_CREAT, 0777); 
		if(fd < 0){
			perror("open error"); 
			exit(1) ;
		}
	char *p = argv[1]; 
	int i; 
	for(i = 0; i < size; i++){
		if (write(fd, (p+i), 1) != 1){
			perror("write error"); 
			exit(1);
		}
		printf("%d success write one character\n", getpid()); 
		sleep(1);
	}
	sleep(5);
	printf("current pid:%d\n", getpid());
	if(!strcmp("'lock", argv[3])){
		//加文件锁(这里是独占写锁)
		//第二个进程想要对文件加锁必须要等到
		//第一个进程释放文件锁后方可枷锁.
		WRITE_LOCKW(fd, 0, SEEK_SET, 0);
		printf("lock success\n");
	}
	if(!strcmp("lock", argv[3])){
		UNLOCK(fd, 0, SEEK_SET, 0);
		printf("unlock success\n");
		printf("unlock pid:%d\n", getpid());
	}
	close(fd);
	return 0;
}
  • 编写start.h脚本文件
bin/lock_write aaaaaa demo.txt Lock &
bin/Lock_write AAAAAA demo.txt lock &

  • 改变脚本如下(由于这里的文件锁是建议性锁,不加锁也能向文件中写入数据)
bin/lock_write aaaaaa demo.txt Lock &
bin/Lock_write AAAAAA demo.txt unlock &

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值