文件锁、进程学习笔记

 概述

        文件锁是一种可以对文件部分或整体加锁的工具
        对于一部分的应用程序而言 为了保证一个进程只能对一个文件进行读写操作 而必须加以文件锁的方式保证数据的正确

        uc提供了两个文件锁函数:flockfcntl

        早期伯克利版本只支持了flock,只能对整个文件加锁,这对效率来说不太友好       

        而fccntl和lockf可以对部分进行加锁下面会介绍

1、flock

这里只简单介绍一下flock因为现在大部分使用fcntl就可以完成对文件的加锁且更灵活

int flock(int fd, int operation);  
//其中fd是文件描述符。

     operation:

     1.LOCK_SH :共享锁

     2.LOCK_EX :排他锁或者独占锁

     3.LOCK_UN : 解锁。

     4.LOCK_NB:非阻塞(与以上三种操作一起使用)

2、fcntl

#include <fcntl.h>

int fcntl (int fd, int cmd, struct flock* lock);

struct flock {
    short int l_type;   // 锁的类型:
                        // F_RDLCK/F_WRLCK/F_UNLCK
                        // (读锁/写锁/解锁)
   short int l_whence;  // 偏移起点:
                        // SEEK_SET/SEEK_CUR/SEEK_END
                        // (文件头/当前位置/文件尾)
    off_t     l_start;  // 锁区偏移,从l_whence开始
    off_t     l_len;    // 锁区长度,0表示锁到文件尾
    pid_t     l_pid;    // 加锁进程,-1表示自动设置
};

 cmd三大取值

F_GETLK  - 测试lock所表示的锁是否可加。       测试模式
           若可加则将lock.l_type置为F_UNLCK,
           否则通过lock返回当前锁的信息。

F_SETLK  - 设置锁定状态为lock.l_type,            不阻塞加锁
          成功返回0,失败返回-1。
          若因其它进程持有锁而导致失败,
           则errno为EACCES或EAGAIN。

F_SETLKW - 设置锁定状态为lock.l_type,        阻塞加锁
           成功返回0,否则一直等待
           除非被信号打断返回-1。

操作锁代码

#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
//控制台读取锁的信息
void read_lock(struct flock *lock){
	printf("输入锁的起始位置参考点(SEEK_SET 0,SEEK_CUR 1,SEEK_END 2):");
	int whence = 0;
	scanf("%d",&whence);
	lock->l_whence = whence==0?SEEK_SET:(whence==1?SEEK_CUR:SEEK_END);
	printf("输入距离参考位置偏移距离:");
	off_t offset = 0;
	scanf("%ld",&offset);
	lock->l_start = offset;
	printf("请输入锁的长度:");
	off_t len = 0;
	scanf("%ld",&len);
	lock->l_len = len;
	lock->l_pid = -1;//自动填充该进程ID
    
}
void write_lock(struct flock *lock){//读出锁的五大信息
	if(lock->l_type == F_RDLCK){
		printf("读锁 ");	
	}else{
		printf("写锁 ");
	}
	int w = lock->l_whence;
	printf("锁的参考位置:%s ",w==SEEK_SET?"SET":(w==SEEK_CUR?"CUR":"END"));
	printf("偏移参考位置距离:%ld ",lock->l_start);
	printf("锁的长度:%ld ",lock->l_len);
	printf("上锁进程为:%d\n",lock->l_pid);
}
void menu(void){
	printf("***文件锁功能测试***\n");
	printf("** 1.上读锁 \n");
	printf("** 2.测试是否可以上读锁 \n");
	printf("** 3.上写锁 \n");
	printf("** 4.测试是否可以上写锁 \n");
	printf("** 5.解锁 \n");
	printf("** 0.退出 \n");
	printf(">>>");
}
void run(void){
	int fd = open("a.txt",O_RDWR);//手动创建a.txt
	if(fd == -1){
		printf("%m\n");
		return;
	}
	printf("进程号:%d\n",getpid());//打印当前进程的进程号!
	struct flock lock = {};//定义一把锁
    //一般都需要定义一把锁 填写锁结构体的信息 随后插入到fd锁指向的文件中
    //做检查操作时 struct flock 类型可以接受信息
	for(;;){
		menu();
		int opt = 0;
		scanf("%d",&opt);
		if(opt>=1 && opt<=4){
			read_lock(&lock);//填写锁信息
			switch(opt){
				case 1:
				case 2:lock.l_type = F_RDLCK;break;
				case 3:
				case 4:lock.l_type = F_WRLCK;break;
			}
			int ret = 0;
			if(opt==2||opt==4){
				ret = fcntl(fd,F_GETLK,&lock);//测试是否可以上锁
      //fcntl 第二个参数F_GETLK是获取fd文件的lock信息
      //返回值如果是0  读取成功
      //如果被上锁 lock的信息会被修改为上锁的信息
      //如果没有被上锁 lock的l_type会被修改为F_UNLCK
				if(ret == 0){
					if(lock.l_type == F_UNLCK){
						printf("可以上锁!\n");	
					}else{
						printf("不可以上锁!\n");
						write_lock(&lock);
					}
				}else{
					printf("获得锁信息失败!\n");	
				}
			}else{
				printf("如果不能上锁,是否一直等待(0.等 1.立即返回):");
				int w = 0;
				scanf("%d",&w);
				int cmd = w==0?F_SETLKW:F_SETLK;
				ret = fcntl(fd,cmd,&lock);
				if(ret == 0){
					printf("上锁成功!\n");	
				}else{
					printf("上锁失败!\n");
					if(errno == EAGAIN || errno == EACCES){
						printf("其他进程已上锁!\n");
					}
				}
			}
		}else if(opt==5){
			lock.l_type = F_UNLCK;//解锁
			printf("请输入解锁的信息:\n");
			read_lock(&lock);
			int ret = fcntl(fd,F_SETLK,&lock);
			if(ret == 0){
				printf("解锁成功!\n");	
			}else{
				printf("解锁失败!\n");	
			}
		}else if(opt == 0){
			break;	
		}else{
			printf("没有该操作!\n");	
		}
	}	
	close(fd);
}

int main(){
	run();
	return 0;	
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值