Linux的IO文件锁示例

一.文件锁的概念

        在Linux操作系统中通常有许多并发型的场景,比如多个用户想要操作同一个一个文件,这样就会导致不知道谁在读或者写文件.那么这个时候文件锁的作用就体现出来了.

        文件锁一般分为共享型锁(读锁)和排他型锁(写锁),那么两种锁的特点,简而言之就是 共享型锁可以共存,排他型锁不能共存.再简而言之,一个文件 A 用户上了读锁,B用户也可以上读锁,但是如果有C上了一个写锁,那么不好意思  排他型 和共享型锁不能共存, 那么则 后上锁的C将会被阻塞,直到文件上的共享型锁都被释放,那么C才能拿到锁.

二.难点讲解    

         现在用一段示例代码解释这个过程:

        上锁这个操作通过fcntl( int fd, "锁的操作", " 锁的结构体 ");这个函数对文件进行上锁,锁定文件通过fd,什么是fd.书接上文socket编程,在linux中这类fd都相当于是文件句柄,linux内一切皆文件,只不过把文件抽象成了一个int类型的数字,我们不用管这个数字的含义,你只管去操作这个数字,linux内核会去帮你操作,相当于linux内核给你提供了一个接口,也就是这个数字接口,一个API,这个数字就相当于文件....  有点啰嗦  下面继续

        有几个部分可能初学者难以理解 一个就是" 锁的结构体 ",另一个就是"锁的操作"

锁的结构体:

通过man fcntl 可以看到帮助文档  

type : 锁的具体类型 读 写 解锁  这个很好理解

whence :  从哪开始  比如文件的开头  当前  末尾  取决于文件的当前指针 有没有设置文件的偏移值

start: 从whence指定 的地方 你想偏移多少 往哪偏移  正数代表往后  -代表往前

len:表示你想锁定多少个字节的文字   0表示全文

pid: 这里主要是记录  是哪个进程给这个文件上锁,一般是默认-1  

struct flock {
               ...
               short l_type;    /* Type of lock: F_RDLCK,
                                   F_WRLCK, F_UNLCK */
               short l_whence;  /* How to interpret l_start:
                                   SEEK_SET, SEEK_CUR, SEEK_END */
               off_t l_start;   /* Starting offset for lock */
               off_t l_len;     /* Number of bytes to lock */
               pid_t l_pid;     /* PID of process blocking our lock
                                   (set by F_GETLK and F_OFD_GETLK) */
               ...
           };

 锁的操作:

锁的操作我概括两种:

1.拿锁 F_GETLK

        拿锁的意思是你可以判断文件中是否有锁,如果有的话可以取出锁的信息并放入锁的结构体中,

上文我讲的type  锁的类型  还有  pid  对文件上锁的进程id,从这体现出其意义.

 2.设置锁 F_SETLKW(阻塞) |  FSETLK(非阻塞)

        设置锁就算是上锁的操作,本质意义上你要上锁的话就要设置好一个锁的结构体,然后进行上锁操作,把结构体和这个文件绑定..   

这里有点区别的是  有无这个 W ,有的话则是阻塞型上锁,有这个W 你去上锁失败,比如文件已经上锁了,他则会阻塞,直到文件无锁,它则直接对其进行上锁,  另一个无阻塞的上锁操作 则是如果文件有锁,则直接返回错误!

 三.具体代码

简述一下整个过程, 创建一个文件并且对其上读锁 并打印出相关的上锁信息  比如谁上的锁  上的什么锁

如果看不懂在干嘛  请反复会看 二  讲的难点讲解  

这里我专门写了给函数方便我进行锁的操作 不够实现上锁 解锁还是依靠fcntl这个函数

你们拿到代码可以开两个客户端实验,同时打开这个文件,因为都是读锁,所以没问题,可以一个文件共存两个共享型锁,但是如果已经上了一个共享型锁,再上一个排他型锁,那么后上锁的那个就会被阻塞,直到第一个用户释放锁.  

#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#define FILE_NAME "lock_file.txt"

int flock_set(int fd,int type)
{
        printf("pid=%d coming!",getpid());
        struct flock fflock;

        memset(&fflock,0,sizeof(struct flock));
        fcntl(fd,F_GETLK,&fflock);
        if(fflock.l_type!=F_UNLCK){
                if(fflock.l_type==F_RDLCK){
                        printf("This file have a ReadLock by pid:%d!\n",fflock.l_pid);
                }else if(fflock.l_type==F_WRLCK){
                        printf("This file have a WriteLock by pid:%d!\n",fflock.l_pid);
                }
        }

        fflock.l_type=type;
        fflock.l_whence=SEEK_SET;
        fflock.l_start=0;
        fflock.l_len=0;
        fflock.l_pid=-1;

        if(fcntl(fd,F_SETLKW,&fflock)<0){
                printf("SETLock ERROR:%s\n",strerror(errno));
        }

        switch(fflock.l_type){
                case F_RDLCK:
printf("The Readlock has been Set by pid:%d!\n",getpid());
                break;
                case F_WRLCK:
                printf("The Writelock has been Set by pid:%d\n",getpid());
                break;
                case F_UNLCK:
                printf("The Unlock has been Set by pid:%d\n",getpid());
                break;
                default:
                break;

        }
        printf("pid:%d out!\n",getpid());
        return 0;
}



int main (void){
        int fd=0;
        fd=open(FILE_NAME,O_RDWR|O_CREAT,0666);
        if(fd<0){
                printf("open error: %s\n",strerror(errno));
                exit(-1);
        }

        flock_set(fd,F_RDLCK);
        getchar();
        flock_set(fd,F_UNLCK);
        getchar();

        close(fd);
        return 0;
}

具体改哪里可以看到效果呢?flock_set(fd,F_WRLCK);  这里改成写锁就可以了 cp 两份代码,一个客户端运行读锁,另一个运行写锁 可以看到马上被阻塞了.

创作不易- -评论点赞 一健三连 支持博主谢谢啦~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值