Linux 文件锁 & pid

本文介绍了Linux下的文件锁定机制,包括创建锁文件和区域锁定两种方式。详细解释了fcntl和lockf系统调用的功能及用法,并指出它们在共享文件访问控制中的作用。

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

    Linux 提供了多种特性来实现文件锁定。

一. 创建锁文件

    许多应用程序只需要能够针对某个资源创建一个锁文件即可,然后,其它程序就可以通过检查这个文件来判断它们自己是否能够被允许访问这个资源。这些锁文件通常被放置在一个特定位置,并带有一个与被控制资源相关的文件名。

    为了创建一个用作锁指示器的文件,可以使用 open 系统调用,并带上 O_CREAT 和 O_EXCL 标志。这样能够以一个原子操作同时完成两项工作:确定文件不存在,然后创建它。程序退出时,需要用 unlink 系统调用删除该锁文件。


二. 区域锁定

    用第一种方法来控制对诸如串口或不经常访问的文件之类的资源的独占式访问,是一个不错的选择,但它并不适用于访问大型的共享文件。此时,可以通过锁定文件区域的方法来解决这个问题。Linux 提供了至少两种方式来实现这一功能:fcntl 系统调用和 lockf 系统调用。

1. fcntl

        #include <fcntl.h>

        int fcntl(int fildes, int command, struct flock *flock_structure);

    第三个 flock 结构依赖具体的实现,但它至少包含下述成员:

        short l_type

        short l_where

        off_t   l_start

        off_t   l_len

        pid_t  l_pid

    l_type 的取值包括:

        F_RDLCK  共享(读写)锁。只要任一进程拥有一把共享锁,那么就没有进程可以再获得该区域上的独占锁

        F_UNLCK  解锁

        F_WRLCK  独占(写)锁,只有一个进程可以在文件的任一特定区域拥有一把独占锁

    l_where、l_start 和 l_len 定义了文件中的一个区域。l_where 的取值必须是 SEEK_SET、SEEK_CUR、SEEK_END 中的一个。

    l_pid 用来记录持有锁的进程。

    第二个参数 command 有 3 个用于文件锁定的命令选项:

        F_GETLK  用于获取 fildes 打开的文件的锁信息,而不会尝试去锁定文件,如果文件已被锁定,l_pid 将被设置成持有锁的进程号

        F_SETLK  用于对 fildes 指向的文件的某个区域加锁或解锁

        F_SETLKW  作用与 F_GETLK 相同,但在无法获取锁时,这个调用将阻塞

    当对文件区域加锁后,必须使用底层的 read 和 write 调用来访问文件中的数据,而不能使用更高级的 fread 和 fwrite 调用,因为后者会缓存。    

2. lockf

        #include <unistd.h>

        int lockf(int fildes, int function, off_t size_to_lock);

    function 参数的取值:

        F_ULOCK  解锁

        F_LOCK     设置独占锁

        F_TLOCK   测试并设置独占锁

        F_TEST      测试其它进程设置的锁

    可以看到,lockf 的接口更简单,但是功能和灵活性都较差,因此不常用,而是作为 fcntl 的补充。


    需要注意,无论是锁文件,还是区域锁定,都仅仅充当一个指示器的角色,程序间需要通过相互协作来使用它们,或者说,都是建议锁,而不是强制锁,它们并不会真正的阻止你读写文件中的数据。

    文件锁的典型使用场景是 pid 文件,用于防止进程启动多个副本。只有获得 pid 文件写入权限(F_WRLCK)的进程才能正常启动,并把自身的 pid 写入该文件中。

    但是看过代码后发现,Apache 和 Memcached 对于防止启动进程的多个副本,实现方式略有不同。

    Apache 的实现方式是,查看 pid 文件记录的进程是否存在:       

        rv = ap_read_pid(pconf, ap_pid_name, &otherpid);
        if (rv != APR_SUCCESS) {
            ......
        } else {
            have_pid_file = 1;
            if (kill(otherpid, 0) == 0) {
                running = 1;
                status = apr_psprintf(pconf, "httpd (pid %"APR_PID_T_FMT") already running", otherpid);
            }
        }

    Memcached 更弱,只要 pid 文件存在,新的进程就无法启动,只能手动删除该 pid 文件然后再重新启动。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值