計算機領域中,鎖機制使用的非常多。它主要是為了避免多個程序訪問同一資源時,可能出現的資料不一致問題。
例如,cat命令輸出乙個比較大的檔案內容,cat命令的特性是需要先將所有磁碟檔案資料讀取到記憶體後再輸出,所以cat輸出乙個大檔案可能需要花費一些時間。如果在cat在載入檔案時,在另乙個終端上向這個檔案追加了一行資料,那麼cat最終載入的資料會包含這行新追加的資料嗎?
再更簡單的乙個示例是,兩個使用者同時用vim開啟乙個檔案去修改資料,那麼以誰修改的資料為準呢?所以,vim為了避免這種問題,每次開啟乙個檔案的時候,都會在檔案的同乙個目錄下建立乙個隱藏的.swp臨時檔案(例如vim a.log
時會生成乙個.a.log.swp
的檔案),如果有其它使用者用vim去開啟同乙個檔案,會檢查這個隱藏檔案是否存在,如果存在說明有人正在編輯這個檔案。
鎖的內容非常多,這裡簡單介紹下它最基本也最實用的基礎知識。
如果不使用鎖,也就是允許多個程序同時更新、讀取同乙份資料,將可能出現以下問題:
1.髒讀:讀取到髒資料。例如使用者a用vim將檔案中的字母x修改為了y,使用者b在vim儲存之前通過cat讀取,得到的這個字母將是x,這種現象稱為髒讀。但其實a已經將它修改為了y,只不過該修改只存在於a的vim快取中,還沒有儲存到磁碟檔案中。通常,將快取中修改後但沒有儲存的資料稱為髒資料。
2.更新丟失:某使用者的資料更新操作被其它使用者覆蓋。例如,使用者a和使用者b同時修改同一檔案中的最後乙個字元a,a將a修改為x,b將a修改為y,那麼a先儲存的話,b的修改將覆蓋a的修改,最終儲存的結果是y,如果b先儲存的話,a的修改將覆蓋b的修改,最終結果得到字元x。所以,同時修改資料時,有乙個程序的更新被覆蓋了,也就是丟失了。
除這兩個問題之外,在多程序同時更新、讀取同乙份資料時,還可能會出現其它現象,這裡不再多做描述。下面介紹一下鎖的機制。
一般鎖分為兩種:共享鎖(shared lock)和互斥鎖(mutex)。共享鎖也稱為讀鎖,常用s字母表示,互斥鎖也稱為排它鎖(exclusive lock)或寫鎖,通常使用x字母表示
當需要讀資料時,將申請讀鎖,當需要修改資料時,將申請寫鎖。
申請鎖的時候,需要先檢查該資源上是否已經有鎖,如果有鎖,檢查已存在的鎖與待申請的鎖是否可以相容共存。
讀鎖和寫鎖的相容性如下表:sx
syesnox
nono
這個相容性是很容易理解的:
這就不難理解,為什麼寫鎖被稱為排它鎖或互斥鎖的緣故:排除異己。
此外,使用鎖需要考慮鎖的粒度,即對多少資源量上鎖。例如,對於乙個檔案來說,可以直接對整個檔案上鎖,也可以只對檔案中想要訪問的那部分資料上鎖。如果直接對整個檔案上鎖,其它程序申請該檔案的互斥鎖將總是被阻塞,而如果只是鎖定該檔案中的前10k資料,那麼其它程序如果申請的互斥鎖從第20k開始的資料,就不會收到影響。
所以,鎖的粒度越大,阻止其它程序的可能性就越大,多程序併發的能力就越差。鎖的粒度越小,阻止其它程序的可能性就越小,併發的能力就越強。
但是,鎖的粒度太小也不一定好,因為每個鎖都是需要額外管理的,粒度越小,需要維護的鎖數量越多。比如頻繁建立鎖和頻繁釋放鎖的開銷並不一定小,甚至在極端的時候比維護單個粗粒度的鎖效率更低。
在shell命令列下,提供了乙個flock命令,它可以通過某個檔案來實現鎖機制:執行某個命令時在某個檔案上申請鎖(讀鎖或寫鎖),另外乙個命令執行時也申請該檔案上的鎖(讀鎖或寫鎖),如果鎖可以共存,則第二個命令可以執行,否則預設阻塞。
下面是shell命令列下flock命令的簡單用法,更詳細內容可man flock自行探索。
1234567
89
# 以下**在終端1上執行
# 在/tmp/a.lock上申請共享鎖(-s),申請成功就執行sleep 10命令
# 因為此時/tmp/a.lock上還沒有任何鎖,所以申請成功
$ flock -s /tmp/a.lock sleep 10
# 以下**在終端2上執行
# 在/tmp/a.lock上申請互斥鎖(-x),申請成功就執行cat /etc/passwd命令
# 因為/tmp/a.lock上已經有共享鎖,所以阻塞,直到10s後共享鎖釋放
$ flock -x /tmp/a.lock cat /etc/passwd
程序間通訊 檔案鎖
int flock int fd,int operation 其中,引數 fd 表示檔案描述符 引數 operation 指定要進行的鎖操作,該引數的取值有如下幾種 lock sh,lock ex,lock un 和 lock mand 通常情況下,如果加鎖請求不能被立即滿足,那麼系統呼叫 floc...
Linux高階程序間通訊 紀錄鎖
加鎖與解鎖 lockit demonstration of fcntl locking include include include includeint main void printf parent locked record n switch fork printf child locked...
php程序間通訊 yoc PHP程序間通訊
php是用c編寫的,因此它對系統底層api的操作與c很像,同大多數語言一樣,php程序間通訊的方式有以下幾種 訊息佇列,管道,共享記憶體,socket和訊號。本文是對這幾種通訊方式對整理 管道通訊pipe 管道用於承載簡稱之間的通訊資料。為了方便理解,可以將管道比作檔案,程序a將資料寫到管道p中,然...