日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux文件(区域)锁函数 -- open()、fcntl()

發布時間:2024/7/19 linux 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux文件(区域)锁函数 -- open()、fcntl() 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一、什么是文件鎖定

對于鎖這個字,大家一定不會陌生,因為我們生活中就存在著大量的鎖,它們各個方面發揮著它的作用,現在世界中的鎖的功能都可歸結為一句話,就是阻止某些人做某些事,例如,門鎖就是阻止除了屋主之外的人進入這個房子,你進入不到這個房子,也就不能使用房子里面的東西。

而因為程序經常需要共享數據,而這通常又是通過文件來實現的,試想一個情況,A進程正在對一個文件進行寫操作,而另一個程序B需要對同一個文件進行讀操作,并以讀取到的數據作為自己程序運行時所需要的數據,這會發生什么情況呢?進程B可能會讀到錯亂的數據,因為它并不知道另一個進程A正在改寫這個文件中的數據。

為了解決類似的問題,就出現了文件鎖定,簡單點來說,這是文件的一種安全的更新方式,當一個程序正在對文件進行寫操作時,文件就會進入一種暫時狀態,在這個狀態下,如果另一個程序嘗試讀這個文件,它就會自動停下來等待這個狀態結束。Linux系統提供了很多特性來實現文件鎖定,其中最簡單的方法就是以原子操作的方式創建鎖文件。

用回之前的例子就是,文件鎖就是當文件在寫的時候,阻止其他的需要寫或者要讀文件的進程來操作這個文件。

二、創建鎖文件

創建一個鎖文件是非常簡單的,我們可以使用open系統調用來創建一個鎖文件,在調用open時oflags參數要增加參數O_CREAT和O_EXCL標志,如file_desc = open("/tmp/LCK.test", O_RDWR|O_CREAT|O_EXCL, 0444);就可以創建一個鎖文件/tmp/LCK.test。O_CREAT|O_EXCL,可以確保調用者可以創建出文件,使用這個模式可以防止兩個程序同時創建同一個文件,如果文件(/tmp/LCK.test)已經存在,則open調用就會失敗,返回-1。

如果一個程序在它執行時,只需要獨占某個資源一段很短的時間,這個時間段(或代碼區)通常被叫做臨界區,我們需要在進入臨界區之前使用open系統調用創建鎖文件,然后在退出臨界區時用unlink系統調用刪除這個鎖文件。

注意:鎖文件只是充當一個指示器的角色,程序間需要通過相互協作來使用它們,也就是說鎖文件只是建議鎖,而不是強制鎖,并不會真正阻止你讀寫文件中的數據。

可以看看下面的例子:源文件文件名為filelock1.c,代碼如下:

#include <unistd.h> #include <stdlib.h> #include <stdio.h> #include <fcntl.h> #include <errno.h>int main() {const char *lock_file = "/tmp/LCK.test1";int n_fd = -1;int n_tries = 10;while (n_tries--){// 創建鎖文件n_fd = open(lock_file, O_RDWR | O_CREAT | O_EXCL, 0444);if (n_fd == -1){// 創建失敗printf("%d - Lock already present\n", getpid());sleep(2);}else{// 創建成功printf("%d - I have exclusive access\n", getpid());sleep(1);close(n_fd);// 刪除鎖文件,釋放鎖unlink(lock_file);sleep(2);}}return 0; }

同時運行同一個程序的兩個實例,運行結果為:

從運行的結果可以看出兩個程序交叉地對對文件進行鎖定,但是真實的操作卻是,每次調用open函數去檢查/tmp/LCK.test1這個文件是否存在,如果存在open調用就失敗,顯示有進程已經把這個文件鎖定了,如果這個文件不存在,就創建這個文件,并顯示許可信息。但是這種做法有一定的缺憾,我們可以看到文件/tmp/LCK.test1被創建了很多次,也被unlink刪除了很多次,也就是說我們不能使用已經事先有數據的文件作為這種鎖文件,因為如果文件已經存在,則open調用總是失敗。

給我的感覺是,這更像是一種對進程工作的協調性安排,更像是二進制信號量的作用,文件存在為0,不存在為1,而不是真正的文件鎖定。

三、區域鎖定

我們還有一個問題,就是如果同一個文件有多個進程需要對它進行讀寫,而一個文件同一時間只能被一個進程進行寫操作,但是多個進程讀寫的區域互不相關,如果總是要等一個進程寫完其他的進程才能對其進行讀寫,效率又太低,那么是否可以讓多個進程同時對文件進行讀寫以提高數據讀寫的效率呢?

為了解決上面提到的問題,和出現在第二點中的問題,即不能把文件鎖定到指定的已存在的數據文件上的問題,我們提出了一種新的解決方案,就是區域鎖定。

簡單點來說,區域鎖定就是,文件中的某個部分被鎖定了,但其他程序可以訪問這個文件中的其他部分。

然而,區域鎖定的創建和使用都比上面說的文件鎖定復雜很多。

1、創建區域鎖定

在Linux上為實現這一功能,我們可以使用fcntl系統調用和lockf調用,但是下面以fcntl系統調用來講解區域鎖定的創建。

fctnl的函數原型為:

int fctnl(int fildes, int command, struct flock *flock_st);

它對一個打開的文件描述進行操作,并能根據command參數的設置完成不同的任務,它有三個可選的任務:F_GETLK,F_SETLK,F_SETLKW,至于這三個參數的意義下面再詳述。而當使用這些命令時,fcntl的第三個參數必須是一個指向flock結構的指針。

2、flock結構

準確來說,flock結構依賴具體的實現,但是它至少包括下面的成員:

short l_type:文件鎖的類型,對應于F_RDLCK(讀鎖,也叫共享鎖),F_UNLCK(解鎖,也叫清除鎖),F_WRLCK(寫鎖,也叫獨占鎖)中的一個。

short l_whence:從文件的哪個相對位置開始計算,對應于SEEK_SET(文件頭),SEEK_CUR(當前位置),SEEK_END(文件尾)中的一個。

off_t l_start:從l_whence開始的第l_start個字節開始計算。

off_t l_len:鎖定的區域的長度。

pid_t l_pid:用來記錄參持有鎖的進程。

成員l_whence、l_start和l_len定義了一個文件中的一個區域,即一個連續的字節集合,例如:

struct flock region; region.l_whence = SEEK_SET; region.l_start = 10; region.l_len = 20;

則表示fcntl函數操作鎖定的區域為文件頭開始的第10到29個字節之間的這20個字節。

3、文件鎖的類型

從上面的flock的成員l_type的取值我們可以知道,文件鎖的類型主要有三種,這里對他們進行詳細的解說。

F_RDLCK

從它的名字我們就可以知道,它是一個讀鎖,也叫共享鎖。許多不同的進程可以擁有文件同一(或重疊)區域上的讀(共享)鎖。而且只要任一進程擁有一把讀(共享)鎖,那么就沒有進程可以再獲得該區域上的寫(獨占)鎖。為了獲得一把共享鎖,文件必須以“讀”或“讀/寫”方式打開。

簡單點來說就是,當一個進程在讀文件中的數據時,文件中的數據不能被改變或改寫,這是為了防止數據被改變而使讀數據的程序讀取到錯亂的數據,而文件中的同一個區域能被多個進程同時讀取,這是容易理解的,因為讀不會破壞數據,或者說讀操作不會改變文件的數據。

F_WRLCK

從它的名字,我們就可以知道,它是一個寫鎖,也叫獨占鎖。只有一個進程可以在文件中的任一特定區域擁有一把寫(獨占)鎖。一旦一個進程擁有了這樣一把鎖,任何其他進程都無法在該區域上獲得任何類型的鎖。為了獲得一把寫(獨占)鎖,文件也必須以“讀”或“讀/寫”方式打開。

簡單點來說,就是一個文件同一區域(或重疊)區域進在同一時間,只能有一個進程能對其進行寫操作,并且在寫操作進行期間,其他的進程不能對該區域進行讀取數據。這個要求是顯然易見的,因為如果兩個進程同時對一個文件進行寫操作,就會使文件的內容錯亂起來,而由于寫時會改變文件中的數據,所以它也不允許其他進程對文件的數據進行讀取和刪除文件等操作。

F_UNLCK:

從它的名字就可以知道,它用于把一個鎖定的區域解鎖。

4、不同的command的意義

在前面說到fcntl函數的command參數時,說了三個命令選項,這里將對它們進行詳細的解說。

F_GETLK命令

它用于獲取fildes(fcntl的第一個參數)打開的文件的鎖信息,它不會嘗試去鎖定文件,調用進程可以把自己想創建的鎖類型信息傳遞給fcntl,函數調用就會返回將會阻止獲取鎖的任何信息,即它可以測試你想創建的鎖是否能成功被創建。fcntl調用成功時,返回非-1,如果鎖請求可以成功執行,flock結構將保持不變,如果鎖請求被阻止,fcntl會用相關的信息覆蓋flock結構。失敗時返回-1。

所以,如果調用成功,調用程序則可以通過檢查flock結構的內容來判斷其是否被修改過,來檢查鎖請求能否被成功執行,而又因為l_pid的值會被設置成擁有鎖的進程的標識符,所以大多數情況下,可以通過檢查這個字段是否發生變化來判斷flock結構是否被修改過。

使用F_GETLK的fcntl函數調用后會立即返回。

舉個例子來說,例如,有一個flock結構的變量,flock_st,flock_st.l_pid = -1,文件的第10~29個字節已經存在一個讀鎖,文件的第40~49個字節中已經存在一個寫鎖,則調用fcntl時,如果用F_GETLK命令,來測試在第10~29個字節中是否可以創建一個讀鎖,因為這個鎖可以被創建,所以,fcntl返回非-1,同時,flock結構的內容也不會改變,flock_st.l_pid = -1。而如果我們測試第40~49個字節中是否可以創建一個寫鎖時,由于這個區域已經存在一個寫鎖,測試失敗,但是fcntl還是會返回非-1,只是flock結構會被這個區域相關的鎖的信息覆蓋了,flock_st.l_pid為擁有這個寫鎖的進程的進程標識符。

F_SETLK命令

這個命令試圖對fildes指向的文件的某個區域加鎖或解鎖,它的功能根據flock結構的l_type的值而定。而對于這個命令來說,flock結構的l_pid字段是沒有意義的。如果加鎖成功,返回非-1,如果失敗,則返回-1。使用F_SETLK的fcntl函數調用后會立即返回。

F_SETLKW命令: (W 表示 wait)

這個命令與前面的F_SETLK,命令作用相同,但不同的是,它在無法獲取鎖時,即測試不能加鎖時,會一直等待直到可以被加鎖為止。

5、例子

看了這么多的說明,可能你已經很亂了,就用下面的例子來整清你的思想吧。

源文件名為filelock2.c,用于創建數據文件,并將文件區域加鎖,代碼如下:

#include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h>int main(int argc, char **argv) {const char *test_file = "./test_lock.txt";int file_desc = -1;int byte_count = 0;char *byte_to_write = "A";struct flock region_1;struct flock region_2;int res = 0;// 打開一個文件m描述符file_desc = open(test_file, O_RDWR|O_CREAT, 0666);if (!file_desc){fprintf(stderr, "Unable to open %s for read/write\n", test_file);exit(EXIT_FAILURE);}// 給文件添加 100個 'A'字符的數據for (byte_count = 0; byte_count < 100; ++byte_count){write(file_desc, byte_to_write, 1);}// 在文件的第 10~29 字節設置讀鎖(共享鎖)region_1.l_type = F_RDLCK;region_1.l_whence = SEEK_SET;region_1.l_start = 10;region_1.l_len = 20;// 在文件的 40~49 字節設置寫鎖(獨占鎖)region_2.l_type = F_WRLCK;region_2.l_whence = SEEK_SET;region_2.l_start = 40;region_2.l_len = 10;printf("Process %d locking file\n", getpid());// 鎖定文件res = fcntl(file_desc, F_SETLK, region_1);if (res == -1){fprintf(stderr, "Failed to lock region 1\n");}res = fcntl(file_desc, F_SETLK, region_2);if (res == -1){fprintf(stderr, "Failed to lock regin 2\n");}// 讓程序休眠1分鐘, 用于測試sleep(60);printf("Process %d closing file\n", getpid());close(file_desc);exit(EXIT_SUCCESS); }

下面的源文件filelock3.c用于測試上一個文件設置的鎖,測試可否對兩個區域都加上一個讀鎖,代碼如下:

#include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h>int main(int argc, char **argv) {const char *test_file = "./test_lock.txt";int file_desc = -1;int res = 0;// 打開數據文件file_desc = open(test_file, O_RDWR|O_CREAT, 0666);if (!file_desc){fprintf(stderr, "Unable to open %s for read/write", test_file);exit(EXIT_FAILURE);}// 設置區域1的鎖類型struct flock region_test1;region_test1.l_type = F_RDLCK;region_test1.l_whence = SEEK_SET;region_test1.l_start = 10;region_test1.l_len = 20;region_test1.l_pid = -1;// 設置區域2的鎖類型struct flock region_test2;region_test2.l_type = F_RDLCK;region_test2.l_whence = SEEK_SET;region_test2.l_start = 40;region_test2.l_len = 10;region_test2.l_pid = -1;// 對區域1的是否可以加一個讀鎖進行測試res = fcntl(file_desc, F_GETLK, region_test1);if (res == -1){fprintf(stderr, "Failed to get RDLCK\n");}if (region_test1.l_pid == -1){// 可以加一個讀鎖printf("test: Process %d could lock\n", getpid());}else{// 不允許加一個讀鎖printf("test:Process %d get lock failure\n", getpid());}// 對q區域2是否可以加一個讀鎖進行測試res = fcntl(file_desc, F_GETLK, region_test2);if (res == -1){fprintf(stderr, "Failed to get RDLCK\n");}if (region_test2.l_pid == -1){// 可以加一個讀鎖printf("test: Process %d could lock\n", getpid());}else{// 不允許加一個鎖printf("test:Process %d get lock failure\n", getpid());}exit(EXIT_SUCCESS); }

運行結果如下:

因為區域1中存在的是讀鎖,所以在其之上再加一個讀鎖是可以成功的,然而區域2上存在的鎖是寫鎖,在其上不能加任何類型的鎖,所以測試失敗。注意,測試失敗并不是fctnl調用失敗,它還是返回非-1,我們是通過檢查flock結構的成員l_pid來確定測試結果的。

三、解空鎖問題

如果我要給在本進程中沒有加鎖的區域解鎖會發生什么事情呢?而如果這個區域中其他的進程有對其進行加鎖又會發生什么情況呢?

如果一個進程實際并未對一個區域進行鎖定,而調用解鎖操作也會成功,但是它并不能解其他的進程加在同一區域上的鎖。也可以說解鎖請求最終的結果取決于這個進程在文件中設置的任何鎖,沒有加鎖,但對其進行解鎖得到的還是沒有加鎖的狀態。

?

?

參考:

Linux C fcntl函數詳解

http://blog.csdn.net/ljianhui/article/details/10075795

《Linux 高性能服務器編程》

轉載于:https://www.cnblogs.com/52php/p/5811965.html

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的Linux文件(区域)锁函数 -- open()、fcntl()的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 女裸全身无奶罩内裤内衣内裤 | 精品无码久久久久久久久 | 黄色网在线免费观看 | 欧美性色视频 | 久久久精品中文字幕麻豆发布 | 国产3页 | 日韩精品成人在线观看 | 久久精品牌麻豆国产大山 | 女儿朋友| 女人脱了内裤趴开腿让男躁 | 日本不卡一区二区三区在线观看 | 久久午夜无码鲁丝片午夜精品 | 找国产毛片看 | 黄色美女片 | av激情在线| 绿帽人妻精品一区二区 | 99青青草 | 一级艳片新婚之夜 | 成人高清免费 | 国产91在线精品 | 欧美国产成人精品一区二区三区 | 岛国大片在线观看 | 丰满人妻综合一区二区三区 | 日韩视频 中文字幕 | 亚洲最新色图 | 两性午夜视频 | 国产伦精品一区二区三区网站 | 亚洲经典在线观看 | 97超碰国产精品无码蜜芽 | 欧美sm凌虐视频网站 | 日韩精品人妻一区 | 欧美日韩激情在线观看 | 91老女人 | 黄色伊人 | 日本成人在线播放 | 懂色视频在线观看 | 人人97 | 老头糟蹋新婚少妇系列小说 | 日日射天天操 | 欧美色图亚洲色 | 日本伦理片在线播放 | 91在线观看 | 911香蕉| 国产精品suv一区二区三区 | 91精品在线看 | 天堂网在线资源 | 奇米av在线| 久久草精品 | 97视频在线观看免费高清完整版在线观看 | a级无毛片| 99re在线国产| 中文字幕一区二区不卡 | 性生交大片免费看 | 女女同性女同一区二区三区按摩 | 亚洲第一区在线播放 | 日本熟妇一区二区三区 | 中文字幕国产一区 | 精品久久久久久久久久久 | 性欧美一区二区 | 久久三级网站 | 国产伦精品一区二区. | 国产片一区二区 | 日本大胆裸体做爰视频 | 国产xxx69麻豆国语对白 | 叶爱在线 | 欧美一级二级三级 | 欧美日韩在线视频观看 | 日韩天堂在线观看 | 涩涩片影院| 天天干在线播放 | 黄色免费小视频 | 69av视频| 国产精品va无码一区二区三区 | 97成人资源站 | 国产在线激情 | 青青操91 | 精品国产系列 | 老头把女人躁得呻吟 | 九草网| 老熟妻内射精品一区 | 黄色h视频 | 国产精品一二三四 | h网站免费在线观看 | 久久草国产 | 激情久久婷婷 | 老司机一区二区三区 | 国产精品亚洲视频 | 中文字幕在线导航 | 国内精品在线播放 | 一集毛片| 波多野吉衣一二三区乱码 | 97看片网 | 香蕉视频最新网址 | 中国肥胖女人真人毛片 | 日本老师巨大bbw丰满 | 久久久久久伦理 | 一眉道姑 电影 | 国产精品伦理一区 | 禁网站在线观看免费视频 |