前言
題目是golang下檔案鎖的使用,但本文的目的其實是通過golang下的檔案鎖的使用方法,來一窺檔案鎖背后的機制,
為什么需要檔案鎖
只有多執行緒/多行程這種并發場景下讀寫檔案,才需要加鎖,
場景1-讀寫并發
讀寫并發場景下,如果不加鎖,就會出現讀到臟資料的情況,想象一下,讀檔案的行程,讀到第500位元組,有其它行程以覆寫寫的方式向檔案中寫入1000位元組,那讀行程讀到的后500位元組就是臟資料,
場景2-寫寫并發
寫寫并發場景下,如果不加鎖,假設A行程先寫0-1000位元組,B行程寫0-900位元組,以此類推,最后一個行程寫0-100位元組,那最終的檔案內容就是每個行程前100個位元組拼接起來的錯亂的內容了,
檔案鎖的幾個概念
共享鎖
共享鎖,也叫讀鎖,某個行程首次獲取共享鎖后,會生成一個鎖型別的變數L,型別標記為共享鎖,其它行程獲取讀鎖的時候,L中的計數器加1,表示又有一個行程獲取到了共享鎖,這個時候如果有行程來獲取排它鎖,會獲取失敗,
排它鎖
排它鎖,也叫寫鎖,某個行程首次獲取排他鎖后,會生成一個鎖型別的變數L,型別標記為排他鎖,其它行程獲取任何型別的鎖的時候,都會獲取失敗,
阻塞
阻塞的意思是說,新的行程發現當前的檔案(資料)被加鎖后,會一直處于等待狀態,直到鎖被釋放,才會繼續下一步的行為,
非阻塞
非阻塞的意思是說,新的行程發現當前的檔案(資料)被加鎖后,立即回傳例外,業務上需要根據具體的業務場景對該例外進行處理,
阻塞和非阻塞其實是行程遇到鎖的時候的兩種處理模式,
golang下如何使用檔案鎖
基本使用
package main
import (
"log"
"os"
"syscall"
)
func main() {
f, err := os.Create("example.txt")
if err != nil {
log.Println("create file example.txt failed", err)
}
defer f.Close()
// 非阻塞模式下,加共享鎖
if err := syscall.Flock(int(f.Fd()), syscall.LOCK_SH|syscall.LOCK_NB); err != nil {
log.Println("add share lock in no block failed", err)
}
// 這里進行業務邏輯
// TODO
// 解鎖
if err := syscall.Flock(int(f.Fd()), syscall.LOCK_UN); err != nil {
log.Println("unlock share lock failed", err)
}
return
}
示例中 LOCK_SH 表示當前獲取的是共享鎖,如果是 LOCK_EX,則表示獲取的是排他鎖,而 LOCK_NB 表示當前獲取鎖的模式是非阻塞模式,如果需要阻塞模式,不加這個引數即可,LOCK_UN 則表示解鎖,即釋放鎖,
golang 下這種檔案鎖的使用方式其實是Linux下的系統級呼叫,使用的是Linux的原生的檔案鎖的相關能力,
使用flock的幾個注意點
1、只要fd指向的是同一個檔案指標,那么加鎖解鎖的行為都是繼承和覆寫的(這個可以看最后的解釋),
2、flock這種方式加的是建議性鎖,也就是說新的行程一上來不管三七二十一,不去通過flock獲取鎖,就對檔案各種操作,也是可以正常生效的,
說一說Linux下面的flock和fcntl
和flock一樣,fcntl也是系統級呼叫,但是在具體的使用上卻有很大不用,并且兩種鎖互不干擾,用flock加鎖,fcntl無法感知,反之也一樣,
建議性鎖和強制鎖
flock加的是建議性鎖,而fcntl加的是強制性鎖,
建議性鎖,本質是一種協議,約定讀寫操作前都去檢查一下該檔案是否有被其它行程加鎖,如果不遵守該協議,一上來就對檔案進行操作,不檢查有沒有鎖,程式執行上是沒有任何問題的,能執行成功,
強制性鎖,才更像真正意義上的鎖,只要加了鎖,其它行程是無法執行非允許的操作的,
其實一些利用redis做的分布式鎖,都是建議性鎖,鎖機的機制要生效,需要大家共同遵守這個約定才行,
全域鎖和區域鎖
對于一個檔案,flock加鎖的范圍是整個檔案內容,而fcntl能對檔案的任意部分加鎖,
鎖的持有者問題
flock認為,鎖的持有者是檔案表(可以理解為檔案指標),所以對于fork和dup操作,他們都對應同一個檔案指標,所有的操作都會作用到這個檔案上,具體表現:
- A行程加鎖,A的子行程行程可以解鎖,新的操作會覆寫之前的操作
- A行程加鎖,A行程復制fd,仍然是可以通過新的fd操作檔案鎖,新的操作會覆寫之前的操作
fcntl 認為,鎖的持有者是行程,加鎖和解鎖的行為都是跟著行程走,具體表現為:
- A行程加鎖,B行程得等A行程消亡或者解鎖才能加鎖
參考
[1] 被遺忘的桃源——flock 檔案鎖
[2] Linux檔案鎖學習-flock, lockf, fcntl
原創不易,歡迎關注我的公眾號:碼農的自由之路
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/230393.html
標籤:其他
下一篇:防止云服務器被爆破的一些措施
