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; } |