此系列笔记参考华清远见《嵌入式 Linux 应用程序开发标准教程》
fcntl()函数
当多个用户共同使用、操作一个文件的情况,这时,Linux 通常采用的方法是给文件上锁,来避免共享的资源产生竞争的状态。
文件锁包括建议性锁和强制性锁。
建议性锁要求每个上锁文件的进程都要检查是否有锁存在,并且尊重已有的锁。(在一般情况下,内核和系统都不使用建议性锁。)
强制性锁是由内核执行的锁,当一个文件被上锁进行写入操作的时候,内核将阻止其他任何文件对其进行读写操作。采用强制性锁对性能的影响很大,每次读写操作都必须检查是否有锁存在。
在 Linux 中,实现文件上锁的函数有 lockf()和 fcntl(),其中 lockf()用于对文件施加建议性锁,而 fcntl()不仅可以施加建议性锁,还可以施加强制锁。同时,fcntl()还能对文件的某一记录上锁,也就是记录锁。
记录锁又可分为读取锁和写入锁,其中读取锁又称为共享锁,它能够使多个进程都能在文件的同一部分建立读取锁。 而写入锁又称为排斥锁, 在任何时刻只能有一个进程在文件的某个部分上建立写入锁。
当然,在文件的同一部分不能同时建立读取锁和写入锁。
fcntl()是一个非常通用的函数,它可以对已打开的文件描述符进行各种操作,不仅包括管理文件锁,还包括获得和设置文件描述符和文件描述符标志、文件描述符的复制等很多功能。下面建立记录锁的方法。
/*lock_set.c*/
int lock_set(int fd,int type)
{
struct flock old_lock,lock;
lock.l_type = type;
lock.l_start = 0;
lock.l_whence = SEEK_SET;
lock.l_len = 0;
lock.l_pid = -1;
//判断文件是否加锁
fcntl(fd,F_GETLK,&lock);
if(lock.l_type != F_UNLCK)
{
//判断问价不能加锁的原因
if(lock.l_type == F_RDLCK) //该文件已有读取锁
{
printf("Read lock already set by %d \n",lock.l_pid);
}else if(lock.l_type == F_WRLCK) //该文件已有写入锁
{
printf("Write lock already set by %d\n", lock.l_pid);
}
}
lock.l_type = type;
//根据不同的type值进行阻塞式上锁或者解锁
if((fcntl(fd,F_SETLKW),&lock)<0)
{
printf("Lock failed:type = %d\n", lock.l_type);
return 1;
}
switch(lock.l_type)
{
case F_RDLCK:
{
printf("Read lock set by %d\n", getpid());
}break;
case F_WRLCK:
{
printf("Write lock set by %d\n", getpid());
}break;
case F_UNLCK:
{
printf("Release lock by %d\n", getpid());
return 1;
}break;
default:break;
}/* end of switch */
return 0;
}
下面的实例是文件写入锁的测试用例,这里首先创建了一个 hello 文件,之后对其上写入锁,最后释放写入锁,代码如下所示:
//write_lock.c
#include <unistd.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include "lock_set.c"
int main()
{
int fd;
//首先打开文件
fd = open("hello",O_RDWR|O_CREAT,0644);
if(fd < 0)
{
printf("Open file Error \n");
exit(1);
}
//给文件加锁
lock_set(fd,F_WRLCK);
getchar();
//给文件解锁
lock_set(fd,F_UNLCK);
getchar();
close(fd);
exit(0);
}
该部分的运行步骤及结果如下:
由此可见,写入锁为互斥锁,同一时刻只能有一个写入锁存在。
接下来的程序是文件读取锁的测试用例,原理和上面的程序一样。
/* read_lock.c */
#include <unistd.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include "lock_set.c"
int main(void)
{
int fd;
fd = open("hello",O_RDWR | O_CREAT, 0644);
if(fd < 0)
{
printf("Open file error\n");
exit(1);
}
/* 给文件上读取锁 */
lock_set(fd, F_RDLCK);
getchar();
/* 给文件解锁 */
lock_set(fd, F_UNLCK);
getchar();
close(fd);
exit(0);
}
由此可见,读取锁为共享锁