本節講述的是利用fcntl函式來實現不同程序間的上鎖,不管這些程序有沒有親緣關係。前面講述過有名訊號量同樣也是可以用在沒有親緣關係的程序間上鎖的。而針對執行緒上鎖的一些機制,想要用在不同程序間上鎖,就需要把鎖放在程序共享記憶體區操作。記錄上鎖主要是用到fcntl 函式。
#include
#include
int fcntl(int fd, int cmd);
int fcntl(int fd, int cmd, long arg);
int fcntl(int fd, int cmd ,struct flock* lock);
返回值:若成功,返回依賴於cmd的值;若出錯,則返回-1,錯誤原因存於errno
引數:
flock 結構體:
//posix只定義fock結構中必須有以下的資料成員,具體實現可以增加 ,而且是不區分順序的 ,所以不能按照順序初始化。
struct flock ;
l_whence 也有三種方式:
l_start:加鎖的起始偏移,相對於l_whence
l_len:指定從該偏移開始的連續位元組,0 表示起始偏移到檔案偏移的最大肯能值,即不管在後面增加多少資料都在鎖的範圍內
l_pid:已經占用鎖的pid(只對f_getlk 命令有效)
鎖住整個檔案有兩種方式:
指定1_whence 成員為seek_set,1_start 成員為0,1_len 成員為0
使用lseek把讀寫指標定位到檔案頭,然後指定 1_whence 成員為 seek_cur,1_start成員為0,1_len 成員為0 。
第一種比較方便,建議使用。
/* lock_fcntl.c*/
#include
#include
#include
#include
#include
#include
#include
#define filename "lock_file"
#define lock
#ifdef lock
void my_lock(int fd)
}void my_unlock(int fd)
}#else
void my_lock(int fd)
void my_unlock(int fd)
#endif
int main (int argc, char **argv)
; int i,n;
int fd = open(filename,o_rdwr | o_creat,0777);
if(fd < 0)
for (i = 0; i < 7; i++)
if (n = read(fd, buff, sizeof(buff) ) < 0)
//sleep(1); //讓實驗效果更加明顯
//buff[n] = '\0';
sscanf(buff, "%ld\n", &count); //把字串轉化成整數儲存到count中
printf("%s: pid = %ld, count = %ld\n", argv[0], (long)getpid(), count);
count++;
memset(buff,0,sizeof(buff));
snprintf(buff, sizeof(buff), "%ld\n", count); //把數字轉化成字串儲存到buff陣列中
if (lseek(fd, 0, seek_set) < 0) //將讀寫位置移到檔案開頭
if (write(fd, buff, strlen(buff)) < 0)
my_unlock(fd); //解鎖
} return
0;
}
關掉巨集 lock 編譯,即不加記錄鎖,同時在後台執行兩個程式,結果如下:
ubuntu:~/test/process_test/lock$ gcc lock_fcntl.c -o lock_fcntl
ubuntu:~/test/process_test/lock$ rm lock_file
ubuntu:~/test/process_test/lock$ ./lock_fcntl & ./lock_fcntl &
./lock_fcntl: pid = 83095, count = 0
./lock_fcntl: pid = 83094, count = 0
./lock_fcntl: pid = 83095, count = 1
./lock_fcntl: pid = 83095, count = 2
./lock_fcntl: pid = 83094, count = 2
./lock_fcntl: pid = 83095, count = 3
./lock_fcntl: pid = 83095, count = 4
./lock_fcntl: pid = 83094, count = 4
./lock_fcntl: pid = 83095, count = 5
./lock_fcntl: pid = 83094, count = 5
./lock_fcntl: pid = 83095, count = 6
./lock_fcntl: pid = 83094, count = 6
./lock_fcntl: pid = 83094, count = 7
./lock_fcntl: pid = 83094, count = 8
例子講述主要有三個步驟:
讀取檔案的資料寫到count變數中
count自加1
把count裡面的資料寫入檔案
在上面的操作中,如果不加鎖,則我們無法保證當前程序和其他程序這幾個步驟是否會交叉。比如,程序一執行到步驟2,讀取到的count變數的值為0,count自加1,count值為1,此時程序二執行到步驟1,讀取到的count值為0。接著程序一把count寫到檔案中。此時,檔案的資料是1,此後程序二也把count變數的值寫資料到檔案,檔案的資料還是1。如果程序一和程序二先後執行的時間足夠長,那麼檔案的資料就會是2。以此類推,我們執行程式後的檔案的資料是小於等於13,一般來說是小於13。而當我們加上鎖之後,因為這幾個步驟是不會出現交叉的行為,所以每次檔案裡面的資料肯定是13。結果如下所示。
開啟巨集 lock 編譯,同時在後台執行兩個程式,結果如下:
ubuntu:~/test/process_test/lock$ gcc lock_fcntl.c -o lock_fcntl
ubuntu:~/test/process_test/lock$ rm lock_file
ubuntu:~/test/process_test/lock$ ./lock_fcntl & ./lock_fcntl &
./lock_fcntl: pid = 83115, count = 0
./lock_fcntl: pid = 83115, count = 1
./lock_fcntl: pid = 83115, count = 2
./lock_fcntl: pid = 83115, count = 3
./lock_fcntl: pid = 83115, count = 4
./lock_fcntl: pid = 83115, count = 5
./lock_fcntl: pid = 83115, count = 6
./lock_fcntl: pid = 83116, count = 7
./lock_fcntl: pid = 83116, count = 8
./lock_fcntl: pid = 83116, count = 9
./lock_fcntl: pid = 83116, count = 10
./lock_fcntl: pid = 83116, count = 11
./lock_fcntl: pid = 83116, count = 12
./lock_fcntl: pid = 83116, count = 13
鎖 記錄上鎖
記錄鎖的功能是 當乙個程序正在讀或者修改檔案的某乙個部分時,它可以阻止其他程序修改同一檔案區。記錄鎖其實是 位元組範圍鎖,因為它鎖定的只是檔案中的乙個區域,也可能是整個檔案。1.基礎介紹 svr3通過fcntl函式增加了記錄鎖功能。fcntl函式的原型已經在以前給出,這邊再重複一次。include ...
UNIX網路程式設計 記錄上鎖
記錄鎖是讀寫鎖的一種擴充套件型別,可用於親緣關係或無親緣關係的程序之間共享某個檔案的讀與寫。被鎖住的檔案通過檔案描述符進行訪問,執行上鎖的操作函式是fcntl,這種型別的鎖通常在核心中維護。記錄鎖的功能是 乙個程序正在讀或修改檔案的某個部分時,可以阻止其他程序修改同一檔案區,即其鎖定的是檔案的乙個區...
UNIX網路程式設計卷二 筆記 讀寫鎖和記錄上鎖
讀寫鎖用於讀取資料比修改資料更頻繁的場景,它的分配規則如下 1.沒有執行緒持有寫鎖時,任意多的執行緒可以持有讀鎖。2.僅當沒有執行緒持有讀鎖或寫鎖時,才能分配寫鎖。當已有執行緒持有讀鎖時,另一線程申請寫鎖則會阻塞,若後續還有讀鎖的申請,此時有兩種策略 1.對後續的讀鎖請求都通過,可能會造成因讀鎖不斷...