浅尝辄止17-Linux基础-文件锁0

当程序猿向程序媛表白时,可能会出现一个糟糕的对话:
猿:“我不喜欢你”
媛:“我知道了”(拉黑)
猿:“还能喜欢谁呢?”——提示:!消息已发出,但被对方拒收了。

可以看出,这个猿犯了两个错误,一是第一句话没有标点,如果加个逗号,则被误解概率会降低(大概万分之一吧),二是没有给对话加锁,下面我们来加个锁。

猿:******表白开始(表白结束前请勿打断!)******
猿:“我不喜欢你,”
媛:“我知道了”(拉黑)——提示:对方表白未结束,请结束后再操作
猿:“还能喜欢谁呢?”
猿:******表白结束******
媛:“我知道了”(拉黑)

这样就完美了,双方都没有误解:)

简介

文件锁就像上面表白开始和结束的声明,在这个声明中间,其它人不可以动这个文件。
Linux文件锁有两种,分别是读锁(劝告/建议性锁)和写锁(排它/独占性锁),顾名思义,其他文件访问者可以知道是否有别人锁了文件,但是读锁不能阻止他修改文件。
Linux文件锁有两套实现,分别是FLOCK和POSIX,两套锁互相无影响。
文件锁主要有三套函数,分别是flock(2),fcntl(2)和lockf(3)

函数名 实现类别 支持读锁 支持写锁 支持文件局部锁
flock FLOCK Χ Χ
lockf POSIX Χ
fcntl POSIX

从表中大概可以猜出来,lockf是用fcntl实现的库函数。

代码演示

只演示flock的使用

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

int main(int argc, char **argv){
    char *filename = "tmp";
    pid_t pid = fork();
    if (pid > 0){//父进程先锁文件,2s后放开
        int fd = open(filename, O_CREAT|O_RDWR|O_TRUNC, 0666);
        if (fd >= 0){
            int ret = flock(fd, LOCK_EX);
            if (!ret){
                printf("[%d] locked\n", getpid());
                sleep(2);
                printf("[%d] unlocked\n", getpid());
                ret = flock(fd,LOCK_UN);
            }
            sleep(1);
            close(fd);
        }
        waitpid(pid,NULL,0);
    }
    else if (pid == 0){//子进程1s后尝试锁文件
        int fd;
        sleep(1);
        fd = open(filename, O_WRONLY);
        if (fd >= 0){
            int ret;
            printf("[%d] opened\n", getpid());
            ret = flock(fd,LOCK_EX|LOCK_NB);
            if (ret) printf("[%d] lockf fail, %s\n", getpid(), strerror(errno));
            ret = write(fd, filename, sizeof(filename));
            if (ret == sizeof(filename)) printf("[%d] write success\n", getpid());
            else printf("[%d] lockf fail, %s\n", getpid(), strerror(errno));
            ret = flock(fd,LOCK_EX);
            if (!ret){
                printf("[%d] locked\n", getpid());
                printf("[%d] unlocked\n", getpid());
                ret = flock(fd,LOCK_UN);
            }
            close(fd);
        }
        exit(EXIT_SUCCESS);
    }
    return 0;
}

输出

[55143] locked
[55144] opened
[55144] lockf fail, Resource temporarily unavailable
[55144] write success
[55143] unlocked
[55144] locked
[55144] unlocked

演示分析

55143为父进程(简称小三),55144为子进程(简称小四)。小三抢先上了锁,小四顺利地打开了文件,然后小四非阻塞上锁失败后,成功地写入了文件。最后小三解锁后,小四才成功获得了锁。
在上述过程中,小四虽然没有获得锁,但是也能成功地写入文件,这印证了它只是个劝告性锁。

关于另外两个函数,未完待续......

你可能感兴趣的:(浅尝辄止17-Linux基础-文件锁0)