Linux文件编程4-文件锁定(fcntl)

文章讲述了Linux中的文件锁定机制,区分了建议性锁和强制性锁,强调了强制性锁能防止并发操作破坏文件,通过示例代码展示了两种锁的使用和效果差异。

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

文件锁定

当多个用户同时操作同一个文件时,为了避免共享资源产生竞争状态,我们可以给文件上锁。文件锁分为建议性锁强制性锁。建议性锁会给文件设置一个标志位,但是,如果对文件操作之前不对该标志位进行检测,那么建议性锁就会形同虚设,其他进程依旧可以对文件进行操作。而强制性锁会让上锁的进程“霸占”这个文件的一些权限,比如一个进程A对文件F设置了一个只允许读操作的强制性锁(读取锁),那么进程B就只能对文件F进行读取,而不能写入或执行,这种锁定状态会一直持续到进程A给文件F解锁。强制性锁可以避免对文件的破坏性操作。当我们使用open、read、write等函数操作文件时,内核都会检测该文件是否被加了强制性锁,如果是,则会导致操作失败。除了锁定文件,文件的某一个状态记录也可以被上锁,称为记录锁

函数和参数

#include <unistd.h>
#include <fcntl.h>
/**
 * @description 默认建议性锁,开启强制性锁需要对系统进行设置
 * @param fd    文件描述符
 * @param cmd   上锁的方式
 * @param lock  上各种锁,锁住哪里
 * @return int  执行成功返回0,执行失败返回-1
 */
int fcntl(int fd, int cmd, struct flock* lock);
cmd作用
F_GETLK根据lock描述,决定是否上锁
F_SETLK根据lock描述,设置锁

结构体flock的定义如下:

struct flock{
    short int l_type;   // 锁定状态
    short int l_whence; // 锁定的起始位置
    off_t     l_start;  // 起始位置相对于l_whence的偏移量
    off_t     l_len;    // 锁定区域的大小
    pid_t     l_pid;    // 执行锁定动作的进程
}
l_type作用
F_RDLCK读取锁,多个进程可以同时建立读取锁
F_WRLCK写入锁,任何时刻只有一个进程可以建立写入锁
F_UNLCK解除锁定

建议性锁

为了测试建议性锁,我们需要两个程序,程序"lockFile.cpp"负责给文件上锁,并持续占用文件;程序"writeFile.cpp"负责检测建议锁,并向文件中写入内容。由于linux默认建议性锁,所以不需要对系统进行额外配置。
"lockFile.cpp"的内容如下:

/**
 * file name:   lockFile.cpp
 */
#include <fcntl.h>
#include <stdio.h>
#include <error.h>
#include <sys/stat.h>
#include <unistd.h>

int main(int argc, char* argv[]){
    struct flock lock;
    int res, fd = open("myFile.txt", O_RDWR|O_CREAT, S_IRWXU);
    if(fd > 0){
        lock.l_type     = F_WRLCK;          // 写入锁
        lock.l_whence   = SEEK_SET;         // 文件起始位置
        lock.l_start    = 0;                // 不偏移
        lock.l_len      = 0;                // 当len=0时代表锁定到文件的末尾;len=非零正整数时代表锁定的字符数
        lock.l_pid      = getpid();         // 获得当前进程pid号

        res = fcntl(fd, F_SETLK, &lock);    // 设置写入锁,不允许其他进程写入

        if(res==0){
            printf("file has been locked. pid:%d\n", getpid());
            while(true);                    // 保持锁定占用状态
        }
    }
    return 0;
}

运行程序后,终端会陷入while函数中,同时输出该进程的PID值为1078
我们打开另一个终端,键入命令,查看该进程是否对文件加锁:

$ sudo cat /proc/locks | grep 1078

2: POSIX ADVISORY WRITE 1078 08:20:3446 0 EOF

从输出中可以看出,该进程加了一个写入锁。

而后,我们通过"writeFile.cpp"文件向"myFile.txt"中写入内容。

#include <fcntl.h>
#include <stdio.h>
#include <error.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>

int main(int argc, char* argv[]){
    struct flock lock;
    int res, fd = open("myFile.txt", O_RDWR|O_CREAT, S_IRWXU);

    if(fd > 0){
        char buf[] = "I have an apple.";
        int count  = strlen(buf);
        int size   = write(fd, buf, count);
        if(size==-1){
            printf("写入失败.\n");
        }
        else{
            printf("写入成功.\n");
        }

        close(fd);
    }

    return 0;
}

执行后发现,可以向"myFile.txt"中写入内容。这就证明了,虽然我们给文件加了写入锁,但由于该锁的性质是建议锁,所以其他进程仍然可以向文件中写入内容。

强制性锁

若要使用强制性锁,需要在root权限下通过mount命令,用-o mand选项来打开该机制。

我们先将"lockFile.cpp"程序终止掉,然后在终端中执行:

$ sudo mount -o remount,mand /

然后重复建议性锁的步骤,发现"writeFile.cpp"无法向"myFile.txt"中写入内容。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值