歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux基礎 >> 關於Linux

Linux系統文件I/O編程(二) 文件鎖函數

上一節:http://blog.csdn.net/mybelief321/article/details/8989755講述的5個基本函數函數open()、 read()、write()、lseek()和close()實現的文件的打開、讀/寫等操作,本節將討論在文件已經共享的情況下 如何操作,也就是當多個用戶共同使用、操作一個文件的情況。這時,Linux通常采用的方法是給文件上鎖, 來避免共享的資源產生競爭的狀態。

文件鎖包括建議性鎖和強制性鎖。建議性鎖要求每個上鎖文件的 進程檢查是否有鎖存在,並且尊重已有的鎖。在一般情況下,內核和系統都不使用建議性鎖。強制性鎖是由內 核執行的鎖,當一個文件被上鎖執行寫入操作時,內核將阻止其他任何文件對其進行讀寫操作。采用強制性鎖 對性能影響很大,每次讀寫都必須檢查是否有鎖存在。

在Linux中,實行文件上鎖的函數有lockf()和 fcntl(),其中lockf()用於對文件施加建議性鎖,而fcntl()不僅可以施加建議性鎖,還可以施加強制性鎖。 同時,fcntl()還能對文件的某一記錄上鎖,也就是記錄鎖。

記錄鎖又可分為讀取鎖和寫入鎖,其中 讀取鎖又稱為共享鎖,它能夠使多個進程都能在文件的同一部分建立讀取鎖。而寫入鎖又稱為排斥鎖,在任何 時刻只能有一個進程在某個部分建立寫入鎖。當然,在文件的同一部分不能同時建立讀取鎖和寫入鎖。

fcntl()函數具有很豐富的功能,它可以對已打開的文件描述符進行各種操作,不僅包括管理文件鎖 ,還包括獲得設置文件描述符和文件描述符標志、文件描述符的復制等很多功能!這一次我先學習一下fcntl ()函數建立文件鎖的方法,關於它的另外的用法...先學會了這個再說吧!

fcntl()函數格式

表1中的lock是一個flock結構體,結構如下:

上圖中的 off_t 就是數據類 型 long int ;pid_t 就是數據類型  int,不懂這裡有解釋:點此解釋

那麼這個結構體lock中每個變量的取值含義如下表2

基礎實驗

本實驗主要是為了練習一下fcntl()函數的文件記錄鎖的功能。下面首先給出了使用 fcntl(0函數的文件記錄鎖功能的代碼實現。

在該代碼中,首先給flock結構體的對應位賦予相應的值 。接著調用兩次fcntl()函數,使用F_GETLK命令判斷是否可以進行flock結構體所描述的鎖操作:若可以進行 ,則flock結構的l_type會被設置為F_UNLCK,其他域不變;若不可進行,則l_pid被設置為擁有文件鎖的進程 號,其他域不變。

用F_SETLK和F_SETLKW命令設置flock結構所描述的鎖操作,後者是前者的阻塞版。

當第一次調用fcntl()時,使用F_FETLK命令獲得當前文件被上鎖的情況,由此可以判斷能不能進行上鎖操 作;當第二次調用fcntl()時,使用F_SETLKW命令對指定文件進行上鎖/解鎖操作。因為F_SETLKW命令是阻塞式 操作,所以,當不能把上鎖/解鎖操作進行下去時,運行會被阻塞,直到能夠進行操作為止。

本次實驗 代碼均上傳到了網站,請自行下載:點此下載

文件記錄鎖的功能代碼具體如下:

/*lock_set.c*/

int lock_set(int fd,int type)

{

struct flock old_lock,lock;  /*定義flock結構體*/

lock.l_whence=SEEK_SET;  /*加鎖整個文件*/

lock.l_start=0;

lock.l_len=0;

lock.l_type=type;

lock.l_pid=-1;

/*判斷文件是否可以上鎖 */

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

 }

}

 

/*l_type 可能在執行完上述判斷後被修改了*/

lock.l_type=type;

/*根據不同的type值進行阻塞式上鎖或解鎖*/

if((fcntl(fd,F_SETLKW,&lock))<0)

{

 printf("Lock failed:type=%d\n",lock.l_type);

 return 1;

}

switch(lock.l_type)

{

 case F_RDLCK:

 {

  printf("Read lock set by %d\n",getpid());/*getpid()用來得到當前的進程號*/

 }

 break;

 case F_WRLCK:

 {

  printf("Write lock set by %d\n",getpid());

 }

 break;

 case F_UNLCK:

 {

  printf("Release lock set by %d\n",getpid());

  return 1;

 }

 break;

 default:break;

}  /*end of switch*/

return 0;

}

下面的代碼是文件寫入鎖的測試用例,這裡首先創建一個hello.c文件,然後對其上鎖,最後釋放寫入鎖。 代碼如下所示:

/*write_lock.c*/

#include<stdio.h>

#include<stdlib.h>

#include<unistd.h>

#include<sys/types.h>

#include<sys/stat.h>

#include<sys/file.h>

#include"lock_set.c"

int main(void)

{

int fd;

 

/*首先打開文件*/

fd=open("/home/song/hello.c",O_RDWR|O_CREAT,0644);

if(fd<0)

{

 printf("Open file error!\n");

 exit(1);

}

 

/*給文件上寫入鎖*/

lock_set(fd,F_WRLCK);

getchar();  /*當用戶輸入任意鍵後,程序繼續執行,否則等待*/

/*給文件解鎖*/

lock_set(fd,F_UNLCK);

getchar();

close(fd);  /*關閉該文件*/

exit(0);

}

文件結構如下圖:

使用命令:gcc write_lock.c -o write_lock編譯

為了使程序有較大的靈活性, 我們的程序中采用文件上鎖後由用戶輸入任意鍵使程序繼續執行。為了更好地顯示寫入鎖的作用,在這裡我們 開兩個終端,並且在終端上同時運行該程序,以達到多個進程操作一個文件的效果。首先運行終端1,請注意 終端2中的第一句話

由上圖可見,寫 入鎖為互斥鎖,同一時刻只能有一個寫入鎖存在。

接下來測試文件讀取鎖,原理和上邊一樣,代碼如 下

/*read_lock.c*/

#include<stdio.h>

#include<stdlib.h>

#include<unistd.h>

#include<sys/types.h>

#include<sys/stat.h>

#include<sys/file.h>

#include"lock_set.c"

int main(void)

{

int fd;

 

/*首先打開文件*/

fd=open("/home/song/hello.c",O_RDWR|O_CREAT,0644);

if(fd<0)

{

 printf("Open file error!\n");

 exit(1);

}

/*給文件上讀取鎖*/

lock_set(fd,F_RDLCK);

getchar();  /*當用戶輸入任意鍵後,程序繼續執行,否則等待*/

/*給文件解鎖*/

lock_set(fd,F_UNLCK);

getchar();  /*當用戶輸入任意鍵後,程序繼續執行,否則等待*/

close(fd);  /*關閉該文件,釋放鎖*/

exit(0);

}

在兩個終端下運行的結果如下圖:

與寫入鎖的運行 結果比較,可有看出,讀取鎖為共享鎖,當進程7170已設置讀取鎖後,進程7294仍然可以設置讀取鎖。

總結:這一節講了文件鎖的問題,那麼咱們再來想一下:為什麼要有文件鎖?原因就是當文件共享, 也就是多個用戶共同使用、操作一個文件的情況,為了避免共享的資源產生競爭的狀態,Linux就采用了給文 件上鎖的方法。

Copyright © Linux教程網 All Rights Reserved