[Linux]--底层文件 I/O 操作之文件锁

本文介绍了Linux环境下文件锁的概念,详细探讨了建议性锁与强制性锁的区别,通过示例代码展示了如何利用fcntl()函数实现文件的读取锁与写入锁。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

此系列笔记参考华清远见《嵌入式 Linux 应用程序开发标准教程》

fcntl()函数
  当多个用户共同使用、操作一个文件的情况,这时,Linux 通常采用的方法是给文件上锁,来避免共享的资源产生竞争的状态。
  文件锁包括建议性锁强制性锁

  建议性锁要求每个上锁文件的进程都要检查是否有锁存在,并且尊重已有的锁。(在一般情况下,内核和系统都不使用建议性锁。)
  强制性锁是由内核执行的锁,当一个文件被上锁进行写入操作的时候,内核将阻止其他任何文件对其进行读写操作。采用强制性锁对性能的影响很大,每次读写操作都必须检查是否有锁存在。

  在 Linux 中,实现文件上锁的函数有 lockf()和 fcntl(),其中 lockf()用于对文件施加建议性锁,而 fcntl()不仅可以施加建议性锁,还可以施加强制锁。同时,fcntl()还能对文件的某一记录上锁,也就是记录锁。
  记录锁又可分为读取锁和写入锁,其中读取锁又称为共享锁,它能够使多个进程都能在文件的同一部分建立读取锁。 而写入锁又称为排斥锁, 在任何时刻只能有一个进程在文件的某个部分上建立写入锁。
  当然,在文件的同一部分不能同时建立读取锁和写入锁。

fcntl()是一个非常通用的函数,它可以对已打开的文件描述符进行各种操作,不仅包括管理文件锁,还包括获得和设置文件描述符和文件描述符标志、文件描述符的复制等很多功能。下面建立记录锁的方法。

/*lock_set.c*/
int lock_set(int fd,int type)
{
    struct flock old_lock,lock;
    lock.l_type = type;
    lock.l_start = 0;
    lock.l_whence = SEEK_SET;
    lock.l_len = 0;
    lock.l_pid = -1;

    //判断文件是否加锁
    fcntl(fd,F_GETLK,&lock);
    if(lock.l_type != F_UNLCK)
    {
        //判断问价不能加锁的原因
        if(lock.l_type == F_RDLCK) //该文件已有读取锁
        {
            printf("Read lock already set by %d \n",lock.l_pid);
        }else if(lock.l_type == F_WRLCK) //该文件已有写入锁
        {
            printf("Write lock already set by %d\n", lock.l_pid);
        }
    }

    lock.l_type = type;

    //根据不同的type值进行阻塞式上锁或者解锁
    if((fcntl(fd,F_SETLKW),&lock)<0)
    {
        printf("Lock failed:type = %d\n", lock.l_type);
        return 1;
    }

    switch(lock.l_type)
    {
        case F_RDLCK:
        {
            printf("Read lock set by %d\n", getpid());
        }break;
        case F_WRLCK:
        {
            printf("Write lock set by %d\n", getpid());
        }break;
        case F_UNLCK:
        {
            printf("Release lock by %d\n", getpid());
            return 1;
        }break;
        default:break;
    }/* end of switch */
    return 0;
}

下面的实例是文件写入锁的测试用例,这里首先创建了一个 hello 文件,之后对其上写入锁,最后释放写入锁,代码如下所示:

//write_lock.c
#include <unistd.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>

#include "lock_set.c"

int main()
{
    int fd;

    //首先打开文件
    fd = open("hello",O_RDWR|O_CREAT,0644);
    if(fd < 0)
    {
        printf("Open file Error \n");
        exit(1);
    }

    //给文件加锁
    lock_set(fd,F_WRLCK);
    getchar();

    //给文件解锁
    lock_set(fd,F_UNLCK);
    getchar();
    close(fd);
    exit(0);
}

该部分的运行步骤及结果如下:

写入锁

由此可见,写入锁为互斥锁,同一时刻只能有一个写入锁存在。

接下来的程序是文件读取锁的测试用例,原理和上面的程序一样。

/* read_lock.c */
#include <unistd.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include "lock_set.c"

int main(void)
{
    int fd;

    fd = open("hello",O_RDWR | O_CREAT, 0644);
    if(fd < 0)
    {
        printf("Open file error\n");
        exit(1);
    }
    /* 给文件上读取锁 */
    lock_set(fd, F_RDLCK);
    getchar();

    /* 给文件解锁 */
    lock_set(fd, F_UNLCK);
    getchar();
    close(fd);
    exit(0);
}

读取锁![](https://img-blog.youkuaiyun.com/20170823171223789?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvd2FuZ3lpamllb25saW5l/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)

由此可见,读取锁为共享锁

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山猫Show

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值