Linux fcntl F_SETLKW实现超时返回

本文详细介绍了如何在Linux下利用fcntl的F_SETLKW选项实现超时返回。通过分析fcntl函数的工作原理,以及利用alarm、_signal函数和定时器等方式,探讨了超时返回的实现策略,包括去除SA_RESTART标志的重要性,以及flock命令的超时实现机制。
摘要由CSDN通过智能技术生成

以下所有代码都是ubuntu20.4系统下运行测试通过

一、函数声明

#include <unistd.h>
#include <fcntl.h>

int fcntl(int fd, int cmd, ... /* arg */ );
//当函数执行失败时返回-1

更多关于fcntl函数,使用和cmd可选参数,请看。
Linux fcntl函数

二、fcntl,F_SETLKW超时返回原理依据

F_SETLKW (struct flock *)
     As for F_SETLK, but if a conflicting lock is held on the file,
    then wait for that lock to be released.  If a signal is caught
    while waiting, then the call is interrupted and (after the
    signal handler has returned) returns immediately (with return
    value -1 and errno set to EINTR; see signal(7)).

摘自:https://man7.org/linux/man-pages/man2/fcntl.2.html

上文中提到,如果在fcntl等待期间,捕获到信号,则这个调用将被打断,并且会立即返回-1,而且设置errno为EINTR。(当然,这个立即返回,是在执行完信号处理函数之后)。

所以基于上面的描述,如果我们要实现,F_SETLKW,3秒后超时返回。那思路就是让这个进程在调用fcntl 3秒后,收到一个信号,中断fcntl的阻塞。【当然这个思路还有一个要考虑的情况,如果我们的fcntl(F_SETLKW)在3秒内成功的获取到了文件读(写)锁,应该取消那个信号的发送。这样才比较合理】

三、实现方式

3.1 通过alarm函数最基础的实现
#include <unistd.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/time.h>
#include <signal.h>


void sig_handler(int sig)
{
   
    if (sig == SIGALRM) {
   
        printf("sig_recv: SIGALRM\n");
    }
}

int main(int argc, char **args)
{
   
    int fd = 0;
    struct flock fl= {
   0};
    char *str_filename, *str_lock_type, *str_start, *str_len, *str_pid;
    int lock_type, start, len, pid;
    if (argc < 5) {
   
        printf(
            "usage: \n"
            "   fcntl_lock [filename] [lock_type] [start] [len] [pid]\n"
            "   lock_type: options is 0(F_RDLCK), 1(O_WRLCK), 2(O_UNLCK)\n"
            "   start: start is base from the start of the file head\n\n"
            "   Remark: the lock range is [start, start + len)\n"
            "   pid: thie param is option, to set the l_pid elem for flock struct\n"
            );
            exit(-1);
    }

    str_filename = args[1];
    str_lock_type = args[2];
    str_start = args[3];
    str_len = args[4];
    str_pid = argc >= 5 ? args[5] : NULL;

    // parse args
    lock_type = atoi(str_lock_type);
    start = atoi(str_start);
    len = atoi(str_len);
    pid = ( str_pid != NULL ? atoi(str_pid) : 0 );

    // check
    if (lock_type != F_RDLCK && lock_type != F_WRLCK && lock_type != F_UNLCK) {
   
        printf("locktype=%d is unalivable\n", lock_type);
        exit(-1);
    }
    if (start < 0) {
   
        printf("start can't set %d, must be positive integer\n", start);
        exit(-1);
    }

    fl.l_whence = SEEK_SET;
    fl.l_type = lock_type;
    fl.l_start = start;
    fl.l_len = len;
    fl.l_pid =  0;str_pid != NULL ? pid: getpid();

    if (fl.l_pid < 0) {
   
        perror("getpid with fail");
        exit(-1);
    }

    fd = open(str_filename, O_CREAT|O_RDWR, S_IRWXU);
    if (fd < 0) {
   
        perror("open test file with fail");
        exit(-1);
    }

    // 
    if (signal(SIGALRM, sig_handler) < 0) {
   
        perror("signal (SIGALRM, sig_handler) with fail"
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值