41-fcntl设置文件锁
1. 文件鎖
當多個進程打開同一文件進行讀寫時可能會出現數據混亂的問題,原因在于進程間共享同一文件讀寫指針位置,也就是f_pos(關于f_pos參考:4-文件描述符與打開的文件之間的關系的第三小節file結構體)。
解決這個問題的方法有很多,比如可以使用信號量完成進程同步,但通常使用文件鎖會更好一些,因為內核會將鎖跟文件關聯起來,這就需要借助fcntl函數來實現對一個文件進行加鎖。只有拿到鎖的進程可以對文件進行讀寫操作,而沒有獲得鎖的進程操作文件可以打開文件,但無法執行read、write操作,以此來防止進程間對同一文件進行讀寫出現的數據混亂問題。
?
2. fcntl函數
#include <unistd.h> #include <fcntl.h>int fcntl(int fd, int cmd, ... /* arg */ );參數fd:指定文件描述符
?
參數cmd:一般用于設置文件鎖,F_SETLK和F_SETLKW 用于加鎖解鎖, F_GETLK用于獲取文件鎖。
F_SETLK設置文件鎖,如果另一進程已經加鎖,那么fcntl將會失敗并返回EAGAIN錯誤,不會阻塞。
F_SETLKW設置文件鎖,如果另一進程已經加鎖,那么該進程將會阻塞,直到文件鎖被釋放。
F_GETLK實際上是用于獲取文件鎖的相關信息,以檢測能否設置F_SETLK或F_SETLKW進行加鎖。
?
參數flock具體定義:
struct flock {...short l_type; //鎖的類型:F_RDLCK(讀方式加鎖) 、F_WRLCK(寫方式加鎖) 、F_UNLCK(解鎖)short l_whence; //參考偏移位置:SEEK_SET、SEEK_CUR、SEEK_END off_t l_start; //具體起始偏移位置,0表示文件開頭off_t l_len; //長度:其實是表示加鎖的范圍(加多少個字節),如果為0表示整個文件加鎖pid_t l_pid; //持有該鎖的進程ID:(只有調用F_GETLK only,才會用到這個參數)... };?
加鎖范圍:
1. 如果 len > 0, [whence+start??,??whence+start+len)?,包左不包右
2. 如果 len = 0, [whence+start??,?∞),包左不包右,表示對整個文件加鎖
以whence為參考位置開始,加上start就是具體的起始位置。例如:whence = SEEK_SET,start = 10,那么參考位置就是文件開頭(偏移為0的位置),加上start后,具體的起始位置就是偏移為10的位置。
?
3. 文件鎖示例
多個進程對加鎖文件進行訪問:
1. 首先測試兩個進程間以讀方式加鎖
2. 然后測試兩個進程間以寫方式加鎖
#include <stdio.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h>void sys_err(char *str){perror(str);exit(1); }int main(int argc, char *argv[]) {int fd;struct flock f_lock;//參數不夠if (argc < 2) {printf("./a.out filename\n");exit(1);}//打開文件失敗if ((fd = open(argv[1] , O_RDWR)) < 0){sys_err("open");}//選用寫瑣f_lock.l_type = F_WRLCK; //選用讀瑣 //f_lock.l_type = F_RDLCK; //設置文件指針為文件開頭f_lock.l_whence = SEEK_SET;//起始偏移,0表示文件開頭f_lock.l_start = 0;// l_len表示加鎖的長度,0表示整個文件加鎖 f_lock.l_len = 0; //設置屬性,讓線程阻塞(F_SETLKW),直到加鎖成功fcntl(fd, F_SETLKW, &f_lock);//如果加鎖成功,打印get flockprintf("get flock\n");//為了測試效果明顯,休眠10秒sleep(10);//設置鎖類型為解鎖f_lock.l_type = F_UNLCK;//設置屬性,解鎖不成功阻塞fcntl(fd, F_SETLKW, &f_lock);//解鎖成功打印unflockprintf("un flock\n");close(fd);return 0; }?
測試兩個進程間以寫方式加鎖,程序執行結果:
從圖中可以看出,以寫方式進行加鎖的話,那么左1進程對文件以寫方式加鎖成功,右1進程對文件以寫方式加鎖會失敗并阻塞,等到左1進程釋放寫鎖后,右1進程立馬獲取到了寫鎖。
?
?
修改部分代碼,測試兩個進程間以讀方式加鎖:
//選用寫瑣 //f_lock.l_type = F_WRLCK; //選用讀瑣 f_lock.l_type = F_RDLCK;以讀方式進行加鎖的話,那么左1進程對文件以讀方式加鎖成功,右1進程對文件以讀方式加鎖也會成功。
由此我們可以得出結論:進程間對文件進行加文件鎖也遵循“讀共享、寫獨占”特性。但!如若進程不加鎖直接操作文件,依然可訪問成功,但數據勢必會出現混亂。
?
?
總結
以上是生活随笔為你收集整理的41-fcntl设置文件锁的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基于JavaScript实现的网页版贪吃
- 下一篇: 金蝶虚拟化客户端连不上服务器,金蝶kis