SylixOS文件記錄鎖使用

1. 文件記錄鎖介紹

文件鎖鎖定的是整個文件,而記錄鎖定還可以鎖定文件的某一特定部分,即從文件的某一相對位置開始的一段連續的字節流。

當一個進程正在讀取或者修改文件的某個部分時,使用文件記錄鎖可以阻止其他進程修改同一文件的相同區域。它可以用來鎖定文件的某個區域或者整個文件,SylixOS 支持多種文件記錄鎖 API

注:SylixOS 支持多種設備驅動模型,但是目前只有 NEW_1 型設備驅動支持文件記錄鎖功能,此類驅動文件節點類似於UNIX 系統的 vnode

2. 文件記錄鎖設置

SylixOS可以通過fcntl 函數操作文件記錄鎖的功能。

2.1 fcntl原型

#include<fcntl.h>

int  fcntl (int  iFd, int  iCmd, ...)

函數fcntl原型分析:

1. 此函數成功時根據參數iCmd的不同而返回不同的值,失敗返回-1並設置錯誤號;

2. 參數 iFd 是文件描述符;

3. 參數 iCmd 是命令;

4. 參數 ...是命令參數。

fcntl設置文件記錄鎖時iCmd對應3個命令:F_GETLKF_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可爲負

l_start是相對l_whence偏移開始位置(注意不可以從文件開始的之前部分鎖起);

l_len是鎖定區域長度,如果爲0則鎖定文件尾(EOF),如果向文件中追加數據也將被鎖;

l_pid是已佔用鎖的進程ID(由命令F_GETLK返回)。

2.2  文件記錄鎖使用規則

文件記錄鎖中的F_RDLOCK(共享讀鎖)F_WRLOCK(獨佔寫鎖)的基本規則是:任意多個進程在一個給定字節上可以有一把共享的讀鎖,但是在一個給定字節上只能有一個進程有一把獨佔的寫鎖。進一步而言,如果在一個給定字節上已經有一把或多把讀鎖,則不能在該字節上再加寫鎖;如果在一個給定字節上有一把寫鎖,則不能再加任何鎖。基本規則如 2-1所示。

表 2-1  記錄鎖規則

當前字節區鎖狀態

請求

讀鎖

寫鎖

無鎖

允許

允許

一個或多個讀鎖

允許

拒絕

一個寫鎖

拒絕

拒絕

上面的規則適用於不同進程提出的鎖請求,並不適用於單個進程提出的鎖請求。也就是說,如果一個進程對一個文件區間已經有了一把鎖,後來該進程又企圖在同一個區間再加一把鎖,那麼也是可以的,這個時候新鎖將替換已有鎖。因此,如果一個進程將某個文件加了一把寫鎖,然後又企圖給文件加一把讀鎖,那麼將會成功執行,原來的寫鎖會被替換爲讀鎖。

2.3  文件記錄鎖特點

  1. 記錄鎖採用(pidstartend)三元組作爲鎖標識,一個文件可擁有多個記錄鎖,同一區域只允許有一個記錄鎖。

  2. 當進程終止(正常/不正常),該進程擁有的所有記錄鎖都將釋放。同一個進程中,指向同一文件(i-node)fd都可以操作該文件上的記錄鎖:如釋放、修改等。顯式調用F_UNLCKclose(fd)都將釋放鎖,close將釋放整個文件中該進程擁有的所有記錄鎖。

  3. 記錄鎖不被spawn的子進程繼承(PID不同)。

記錄鎖的類型轉換、改變鎖範圍等操作均爲原子操作。

未設置FD_CLOEXEC時,記錄鎖將被exec後的進程繼承(PID相同)。

記錄鎖對文件打開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"

intmain(intargc, 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_SETl_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"

intmain(intargc, 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_SETl_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;

}

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章