fcntl函數的使用詳解

來源:互聯網
上載者:User

(1)fcntl函數說明前面的這5個基本函數實現了檔案的開啟、讀寫等基本操作,這一節將討論的是,在文 件已經共用的情況下如何操作,也就是當多個使用者共同使用、操作一個檔案的情況,這時,Linux 通常採用的方法是給檔案上鎖,來避免共用的資源產生競爭的狀態。檔案鎖包括建議性鎖和強制性鎖。建議性鎖要求每個上鎖檔案的進程都要檢查是否有鎖存,並且尊重已有的鎖。在一般情況下,核心和系統都不使用建議性鎖。強制性鎖是由內 核執行的鎖,當一個檔案被上鎖進行寫入操作的時候,核心將阻止其他任何檔案對其進行讀寫操作。採用強制性鎖對效能的影響很大,每次讀寫操作都必須檢查是否有鎖存在。在 Linux 中,實現檔案上鎖的函數有lock和fcntl,其中flock用於對檔案施加建議性鎖,而fcntl不僅可以施加建議性鎖,還可以施加強制鎖。同時,fcntl還能對檔案的某一記錄進行上鎖,也就是記錄鎖。記錄鎖又可分為讀取鎖和寫入鎖,其中讀取鎖又稱為共用鎖定,它能夠使多個進程都能在檔案的同一部分建立讀取鎖。而寫入鎖又稱為排斥鎖,在任何時刻只能有一個進程在檔案的某個部分上建立寫入鎖。當然,在檔案的同一部分不能同時建立讀取鎖和寫入鎖。注意:fcntl是一個非常通用的函數,它還可以改變檔案進程各方面的屬性,在本節中,主要介紹它建立記錄鎖的方法,關於它其他使用者感興趣的讀者可以參看fcntl手冊。 (2)fcntl函數格式用於建立記錄鎖的fcntl函數格式如表6.6 所示。表6.6 fcntl函數文法要點所需標頭檔 複製代碼 代碼如下:#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>

函數原型int fcnt1(int fd, int cmd, struct flock *lock)fd:檔案描述符F_DUPFD:複製檔案描述符F_GETFD:獲得fd的close-on-exec標誌,若標誌未設定,則檔案經過exec函數之後仍保持開啟狀態F_SETFD:設定close-on-exec標誌,該標誌以參數arg的FD_CLOEXEC位決定F_GETFL:得到open設定的標誌函數傳入值cmdF_SETFL:改變open設定的標誌F_GETFK:根據lock描述,決定是否上檔案鎖F_SETFK:設定lock描述的檔案鎖F_SETLKW:這是F_SETLK的阻塞版本(命令名中的W表示等待(wait))。如果存在其他鎖,則調用進程睡眠;如果捕捉到訊號則睡眠中斷F_GETOWN:檢索將收到SIGIO和SIGURG訊號的進程號或進程組號F_SETOWN:設定進程號或進程組號函數傳回值Lock:結構為flock,設定記錄鎖的具體狀態,後面會詳細說明成功:0-1:出錯這裡,lock的結構如下所示:複製代碼 代碼如下:Struct flock{
short l_type;
off_t l_start;
short l_whence;
off_t l_len;
pid_t l_pid;
}lock結構中每個變數的取值含義如表6.7 所示。表6.7 lock結構變數取值

F_RDLCK:讀取鎖(共用鎖定)l_type F_WRLCK:寫入鎖(排斥鎖)F_UNLCK:解鎖l_stat 相對位移量(位元組)SEEK_SET:當前位置為檔案的開頭,新位置為位移量的大小SEEK_CUR:當前位置為檔案指標的位置,新位置為當前位置加上位移量l_whence:相對位移量的起點(同lseek 的whence)。SEEK_END:當前位置為檔案的結尾,新位置為檔案的大小加上位移量的大小l_len 加鎖地區的長度
小技巧:為加鎖整個檔案,通常的方法是將l_start 說明為0,l_whence 說明為SEEK_SET,l_len 說明為0。 (3)fcntl使用執行個體下面首先給出了使用fcntl 函數的檔案記錄鎖函數。在該函數中,首先給flock 結構體的對應位賦予相應的值。接著使用兩次fcntl函數分別用於給相關檔案上鎖和判斷檔案是否可以上鎖,這裡用到的cmd值分別為F_SETLK 和F_GETLK。這個函數的原始碼如下所示: 複製代碼 代碼如下:/*lock_set函數*/
void lock_set(int fd, int type)
{
struct flock lock;
lock.l_whence = SEEK_SET;//賦值lock結構體
lock.l_start = 0;
lock.l_len =0;
while(1){
lock.l_type = type;
/*根據不同的type值給檔案上鎖或解鎖*/
if((fcntl(fd, F_SETLK, &lock)) == 0){
if( lock.l_type == F_RDLCK )
printf("read lock set by %d\n",getpid());
else if( lock.l_type == F_WRLCK )
printf("write lock set by %d\n",getpid());
else if( lock.l_type == F_UNLCK )
printf("release lock by %d\n",getpid());
return;
}
/*判斷檔案是否可以上鎖*/
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);
getchar();
}
}
}

下面的執行個體是測試檔案的寫入鎖,這裡首先建立了一個hello檔案,之後對其上寫入鎖,最後釋放寫入鎖。代碼如下所示:複製代碼 代碼如下:/*fcntl_write.c測試檔案寫入鎖主函數部分*/
#include <unistd.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int fd;
/*首先開啟檔案*/
fd=open("hello",O_RDWR | O_CREAT, 0666);
if(fd < 0){
perror("open");
exit(1);
}
/*給檔案上寫入鎖*/
lock_set(fd, F_WRLCK);
getchar();
/*給檔案接鎖*/
lock_set(fd, F_UNLCK);
getchar();
close(fd);
exit(0);
}

為了能夠使用多個終端,更好地顯示寫入鎖的作用,本執行個體主要在PC 機上測試,讀者可將其交叉編譯,下載到目標板上運行。下面是在PC 機上的運行結果。為了使程式有較大的靈活性,筆者採用檔案上鎖後由使用者鍵入一任意鍵使程式繼續運行。建議讀者開啟兩個終端,並且在兩個終端上同時運行該程式,以達到多個進程操作一個檔案的效果。在這裡,筆者首先運行終端一,請讀者注意終端二中的第一句。
終端一:
複製代碼 代碼如下:[root@localhost file]# ./fcntl_write
write lock set by 4994
release lock by 4994

終端二:
複製代碼 代碼如下:[root@localhost file]# ./fcntl_write
write lock already set by 4994
write lock set by 4997
release lock by 4997

由此可見,寫入鎖為互斥鎖,一個時刻只能有一個寫入鎖存在。
接下來的程式是測試檔案的讀取鎖,原理同上面的程式一樣。複製代碼 代碼如下:/*fcntl_read.c測試檔案讀取鎖主函數部分*/
#include <unistd.h>
#include <sys/file.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int fd;
fd=open("hello",O_RDWR | O_CREAT, 0666);
if(fd < 0){
perror("open");
exit(1);
}
/*給檔案上讀取鎖*/
lock_set(fd, F_RDLCK);
getchar();
/*給檔案接鎖*/
lock_set(fd, F_UNLCK);
getchar();
close(fd);
exit(0);
}

同樣開啟兩個終端,並首先啟動終端一上的程式,其運行結果如下所示:
終端一:
複製代碼 代碼如下:[root@localhost file]# ./fcntl2
read lock set by 5009
release lock by 5009

終端二:
複製代碼 代碼如下:[root@localhost file]# ./fcntl2
read lock set by 5010
release lock by 5010

讀者可以將此結果與寫入鎖的運行結果相比較,可以看出,讀取鎖為共用鎖定,當進程5009已設定讀取鎖後,進程5010 還可以設定讀取鎖。
思考:
如果在一個終端上回合設定讀取鎖,則在另一個終端上回合設定寫入鎖,會有什麼結果呢?

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.