简介
文件锁主要有三套函数,分别是flock(2),fcntl(2)和lockf(3)
函数名 | 实现类别 | 支持读锁 | 支持写锁 | 支持文件局部锁 |
---|---|---|---|---|
flock | FLOCK | ∨ | Χ | Χ |
lockf | POSIX | Χ | ∨ | ∨ |
fcntl | POSIX | ∨ | ∨ | ∨ |
从表中大概可以猜出来,lockf是用fcntl实现的库函数,不过这并不绝对,lockf与fcntl的关系并没有标准,例如在mac系统中,lockf就是劝告性锁。
代码演示
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
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, 0666);
if (fd >= 0){
int ret = lockf(fd, F_LOCK, 0);
if (!ret){
printf("[%d] locked\n", getpid());
sleep(2);
printf("[%d] unlocked\n", getpid());
ret = lockf(fd, F_ULOCK, 0);
}
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 = lockf(fd, F_TLOCK, 0);
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 = lockf(fd, F_LOCK, 0);
if (!ret){
printf("[%d] locked\n", getpid());
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));
printf("[%d] unlocked\n", getpid());
ret = lockf(fd, F_ULOCK, 0);
}
close(fd);
}
exit(EXIT_SUCCESS);
}
return 0;
}
输出
[5165] locked
[5166] opened
[5166] lockf fail, Resource temporarily unavailable
[5166] write success
[5165] unlocked
[5166] locked
[5166] write success
[5166] unlocked
在父进程上锁后,子进程分别进行了非阻塞申请锁和阻塞申请锁,非阻塞申请立刻返回错误,阻塞申请就一直等到父进程释放。
为什么子进程没拿到锁,也同样写入成功了?