在golang中,可以利用sync包的api來實現檔案鎖。檔案鎖(flock)是對於整個檔案的建議性鎖;也就是說,如果一個程序在一個檔案(inode)上放了鎖,其它程序是可以知道的(建議性鎖不強求程序遵守);檔案鎖的呼叫語法「syscall.Flock(int(f.Fd()), syscall.LOCK_EX|syscall.LOCK_NB)」。
php入門到就業線上直播課:進入學習
Apipost = Postman + Swagger + Mock + Jmeter 超好用的API偵錯工具:
本教學操作環境:windows7系統、GO 1.18版本、Dell G3電腦。
我們使用Go語言開發一些程式的時候,往往出現多個程序同時操作同一份檔案的情況,這很容易導致檔案中的資料混亂。這時我們就需要採用一些手段來平衡這些衝突,檔案鎖(flock)應運而生,下面我們就來介紹一下。
對於 flock,最常見的例子就是 Nginx,程序執行起來後就會把當前的 PID 寫入這個檔案,當然如果這個檔案已經存在了,也就是前一個程序還沒有退出,那麼 Nginx 就不會重新啟動,所以 flock 還可以用來檢測程序是否存在。
flock 是對於整個檔案的建議性鎖。也就是說,如果一個程序在一個檔案(inode)上放了鎖,其它程序是可以知道的(建議性鎖不強求程序遵守)。最棒的一點是,它的第一個引數是檔案描述符,在此檔案描述符關閉時,鎖會自動釋放。而當程序終止時,所有的檔案描述符均會被關閉。所以很多時候就不用考慮類似原子鎖解鎖的事情。
在具體介紹前,先上程式碼
package main
import (
"fmt"
"os"
"sync"
"syscall"
"time"
)
//檔案鎖
type FileLock struct {
dir string
f *os.File
}
func New(dir string) *FileLock {
return &FileLock{
dir: dir,
}
}
//加鎖
func (l *FileLock) Lock() error {
f, err := os.Open(l.dir)
if err != nil {
return err
}
l.f = f
err = syscall.Flock(int(f.Fd()), syscall.LOCK_EX|syscall.LOCK_NB)
if err != nil {
return fmt.Errorf("cannot flock directory %s - %s", l.dir, err)
}
return nil
}
//釋放鎖
func (l *FileLock) Unlock() error {
defer l.f.Close()
return syscall.Flock(int(l.f.Fd()), syscall.LOCK_UN)
}
func main() {
test_file_path, _ := os.Getwd()
locked_file := test_file_path
wg := sync.WaitGroup{}
for i := 0; i < 10; i++ {
wg.Add(1)
go func(num int) {
flock := New(locked_file)
err := flock.Lock()
if err != nil {
wg.Done()
fmt.Println(err.Error())
return
}
fmt.Printf("output : %d\n", num)
wg.Done()
}(i)
}
wg.Wait()
time.Sleep(2 * time.Second)
}
登入後複製
在 Windows 系統下執行上面的程式碼會出現下面的錯誤:
這是因為 Windows 系統不支援 pid 鎖,所以我們需要在 Linux 或 Mac 系統下才能正常執行上面的程式。
上面程式碼中演示了同時啟動 10 個 goroutinue,但在程式執行過程中,只有一個 goroutine 能獲得檔案鎖(flock)。其它的 goroutinue 在獲取不到 flock 後,會丟擲異常的資訊。這樣即可達到同一檔案在指定的週期內只允許一個程序存取的效果。
程式碼中檔案鎖的具體呼叫:
syscall.Flock(int(f.Fd()), syscall.LOCK_EX|syscall.LOCK_NB)
登入後複製
我們採用了 syscall.LOCK_EX、syscall.LOCK_NB,這是什麼意思呢?
flock 屬於建議性鎖,不具備強制性。一個程序使用 flock 將檔案鎖住,另一個程序可以直接操作正在被鎖的檔案,修改檔案中的資料,原因在於 flock 只是用於檢測檔案是否被加鎖,針對檔案已經被加鎖,另一個程序寫入資料的情況,核心不會阻止這個程序的寫入操作,也就是建議性鎖的核心處理策略。
flock 主要三種操作型別:
LOCK_SH:共用鎖,多個程序可以使用同一把鎖,常被用作讀共用鎖;
LOCK_EX:排他鎖,同時只允許一個程序使用,常被用作寫鎖;
LOCK_UN:釋放鎖。
程序使用 flock 嘗試鎖檔案時,如果檔案已經被其他程序鎖住,程序會被阻塞直到鎖被釋放掉,或者在呼叫 flock 的時候,採用 LOCK_NB 引數。在嘗試鎖住該檔案的時候,發現已經被其他服務鎖住,會返回錯誤,錯誤碼為 EWOULDBLOCK。
flock 鎖的釋放非常具有特色,即可呼叫 LOCK_UN 引數來釋放檔案鎖,也可以通過關閉 fd 的方式來釋放檔案鎖(flock 的第一個引數是 fd),意味著 flock 會隨著程序的關閉而被自動釋放掉。
更多程式設計相關知識,請存取:!!
以上就是golang怎麼實現檔案鎖的詳細內容,更多請關注TW511.COM其它相關文章!