文章目录
以下所有代码都是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)).
上文中提到,如果在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"