1. 文件记录锁介绍
文件锁锁定的是整个文件,而记录锁定还能够锁定文件的某一特定部分,即从文件的某一相对位置开始的一段连续的字节流。node
当一个进程正在读取或者修改文件的某个部分时,使用文件记录锁能够阻止其余进程修改同一文件的相同区域。它能够用来锁定文件的某个区域或者整个文件,SylixOS 支持多种文件记录锁 API。app
注:SylixOS 支持多种设备驱动模型,可是目前只有 NEW_1 型设备驱动支持文件记录锁功能,此类驱动文件节点相似于UNIX 系统的 vnode。函数
2. 文件记录锁设置
SylixOS能够经过fcntl 函数操做文件记录锁的功能。spa
2.1 fcntl原型
#include <fcntl.h>指针 int fcntl (int iFd, int iCmd, ...)继承 |
函数fcntl原型分析:进程
1. 此函数成功时根据参数iCmd的不一样而返回不一样的值,失败返回-1并设置错误号;ci
2. 参数 iFd 是文件描述符;原型
3. 参数 iCmd 是命令;it
4. 参数 ...是命令参数。
fcntl设置文件记录锁时iCmd对应3个命令:F_GETLK、F_SETLK 和 F_SETLKW。命令解释分别是:F_GETLK表示获取文件锁;F_SETLK表示设置文件锁(非阻塞);F_SETLKW表示设置文件锁(阻塞)。第 3 个参数是一个 flock 结构体指针,结构体成员如程序清单 2‑1所示。
程序清单 2‑1 flock结构体成员
struct flock { short l_type; /* F_RDLCK, F_WRLCK, or F_UNLCK */ short l_whence; /* flag to choose starting */ /* offset */ off_t l_start; /* relative offset, in bytes */ off_t l_len; /* length, in bytes; 0 means */ /* lock to EOF */ pid_t l_pid; /* returned with F_GETLK */ long l_xxx[4]; /* reserved for future use */ }; |
1. l_type表示锁的类型分别为:F_RDLOCK(共享读锁)、F_WRLOCK(独占写锁)和F_UNLCK(解锁);
2. l_whence表示文件记录锁的起始位置,其值如图 2‑1所示。
图 2‑1 l_Whence值相关
iWhence 值 |
oftOffset 说明 |
SEEK_SET |
将文件的偏移量设置为距文件开始处 oftOffset 个字节 |
SEEK_CUR |
将文件的偏移量设置为当前值加oftOffset个字节,oftOffset可为负 |
SEEK_END |
将文件的偏移量设置为文件长度加oftOffset个字节,oftOffset可为负 |
3. l_start是相对l_whence偏移开始位置(注意不能够从文件开始的以前部分锁起);
4. l_len是锁定区域长度,若是为0则锁定文件尾(EOF),若是向文件中追加数据也将被锁;
5. l_pid是已占用锁的进程ID(由命令F_GETLK返回)。
2.2 文件记录锁使用规则
文件记录锁中的F_RDLOCK(共享读锁)和F_WRLOCK(独占写锁)的基本规则是:任意多个进程在一个给定字节上能够有一把共享的读锁,可是在一个给定字节上只能有一个进程有一把独占的写锁。进一步而言,若是在一个给定字节上已经有一把或多把读锁,则不能在该字节上再加写锁;若是在一个给定字节上有一把写锁,则不能再加任何锁。基本规则如表 2‑1所示。
表 2‑1 记录锁规则
上面的规则适用于不一样进程提出的锁请求,并不适用于单个进程提出的锁请求。也就是说,若是一个进程对一个文件区间已经有了一把锁,后来该进程又企图在同一个区间再加一把锁,那么也是能够的,这个时候新锁将替换已有锁。所以,若是一个进程将某个文件加了一把写锁,而后又企图给文件加一把读锁,那么将会成功执行,原来的写锁会被替换为读锁。
2.3 文件记录锁特色
1. 记录锁采用(pid,start,end)三元组做为锁标识,一个文件可拥有多个记录锁,同一区域只容许有一个记录锁。
2. 当进程终止(正常/不正常),该进程拥有的全部记录锁都将释放。同一个进程中,指向同一文件(i-node)的fd均可以操做该文件上的记录锁:如释放、修改等。显式调用F_UNLCK和close(fd)都将释放锁,close将释放整个文件中该进程拥有的全部记录锁。
3. 记录锁不被spawn的子进程继承(PID不一样)。
4. 记录锁的类型转换、改变锁范围等操做均为原子操做。
5. 未设置FD_CLOEXEC时,记录锁将被exec后的进程继承(PID相同)。
6. 记录锁对文件打开mode有要求:加读锁要求文件句柄fd有读权限,加写锁要求fd有写权限。
3. 文件记录锁使用
好比进程A对文件“/apps/file”加上写锁(进程A先上锁),当A进程用户操做结束后会释放锁给进程B操做,进程A代码如程序清单 3‑1所示。
程序清单 3‑1 进程A代码
#include <stdio.h> #include <unistd.h> #include <fcntl.h>
#define FILE_PATH "/apps/file" int main(int argc, char *argv[]) { int iFd = 0; struct flock flck; short sLockt = F_WRLCK;
iFd = open(FILE_PATH, O_RDWR); /* 打开文件 */ if (iFd < 0) { fprintf(stderr, "open file failed.\n"); return -1; } /* * l_whence = SEEK_SET;l_start = 0;表示从文件开始起偏移量为0开始上锁 * l_len = 0;表示锁定到文件尾 */ flck.l_type = sLockt; /* 文件记录锁类型设置为独写锁 */ flck.l_whence = SEEK_SET; flck.l_start = 0; flck.l_len = 0;
if (fcntl(iFd, F_SETLK, &flck) < 0) { /* fcntl设置文件记录锁 */ fprintf(stderr, "add write lock failed.\n"); close(iFd); return -1; } /* * 用户对文件被锁定区域操做 */ sLockt = F_UNLCK; /* 文件记录锁类型设置为解锁 */ flck.l_type = sLockt; flck.l_whence = SEEK_SET; flck.l_start = 0; flck.l_len = 0;
if (fcntl(iFd, F_SETLK, &flck) < 0) { fprintf(stderr, "unlock failed.\n"); close(iFd); return -1; } close(iFd); return 0; } |
进程B也对文件“/apps/file”操做,区别是进程B设置为F_SETLKW(阻塞等待解锁)。进程B阻塞等待进程A解锁方可对文件进行操做,进程B代码如程序清单 3‑2所示。
程序清单 3‑2 进程B代码
#include <stdio.h> #include <unistd.h> #include <fcntl.h>
#define FILE_PATH "/apps/file" int main(int argc, char *argv[]) { int iFd = 0; struct flock flck; short sLockt = F_WRLCK;
iFd = open(FILE_PATH, O_RDWR); /* 打开文件 */ if (iFd < 0) { fprintf(stderr, "open file failed.\n"); return -1; } /* * l_whence = SEEK_SET;l_start = 0;表示从文件开始起偏移量为0开始上锁 * l_len = 0;表示锁定到文件尾 */ flck.l_type = sLockt; /* 文件记录锁类型设置为独写锁 */ flck.l_whence = SEEK_SET; flck.l_start = 0; flck.l_len = 0;
if (fcntl(iFd, F_SETLKW, &flck) < 0) { /* fcntl设置文件记录锁 */ fprintf(stderr, "add write lock failed.\n"); close(iFd); return -1; } /* * 用户对文件被锁定区域进行操做 */ close(iFd); return 0; } |