新聞中心
我們使用Go語言開發(fā)一些程序的時(shí)候,往往出現(xiàn)多個(gè)進(jìn)程同時(shí)操作同一份文件的情況,這很容易導(dǎo)致文件中的數(shù)據(jù)混亂。這時(shí)我們就需要采用一些手段來平衡這些沖突,文件鎖(flock)應(yīng)運(yùn)而生,下面我們就來介紹一下。

公司主營業(yè)務(wù):做網(wǎng)站、成都做網(wǎng)站、移動(dòng)網(wǎng)站開發(fā)等業(yè)務(wù)。幫助企業(yè)客戶真正實(shí)現(xiàn)互聯(lián)網(wǎng)宣傳,提高企業(yè)的競爭能力。創(chuàng)新互聯(lián)建站是一支青春激揚(yáng)、勤奮敬業(yè)、活力青春激揚(yáng)、勤奮敬業(yè)、活力澎湃、和諧高效的團(tuán)隊(duì)。公司秉承以“開放、自由、嚴(yán)謹(jǐn)、自律”為核心的企業(yè)文化,感謝他們對我們的高要求,感謝他們從不同領(lǐng)域給我們帶來的挑戰(zhàn),讓我們激情的團(tuán)隊(duì)有機(jī)會(huì)用頭腦與智慧不斷的給客戶帶來驚喜。創(chuàng)新互聯(lián)建站推出米林免費(fèi)做網(wǎng)站回饋大家。
對于 flock,最常見的例子就是 Nginx,進(jìn)程運(yùn)行起來后就會(huì)把當(dāng)前的 PID 寫入這個(gè)文件,當(dāng)然如果這個(gè)文件已經(jīng)存在了,也就是前一個(gè)進(jìn)程還沒有退出,那么 Nginx 就不會(huì)重新啟動(dòng),所以 flock 還可以用來檢測進(jìn)程是否存在。
flock 是對于整個(gè)文件的建議性鎖。也就是說,如果一個(gè)進(jìn)程在一個(gè)文件(inode)上放了鎖,其它進(jìn)程是可以知道的(建議性鎖不強(qiáng)求進(jìn)程遵守)。最棒的一點(diǎn)是,它的第一個(gè)參數(shù)是文件描述符,在此文件描述符關(guān)閉時(shí),鎖會(huì)自動(dòng)釋放。而當(dāng)進(jìn)程終止時(shí),所有的文件描述符均會(huì)被關(guān)閉。所以很多時(shí)候就不用考慮類似原子鎖解鎖的事情。
在具體介紹前,先上代碼
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 系統(tǒng)下運(yùn)行上面的代碼會(huì)出現(xiàn)下面的錯(cuò)誤:
undefined: syscall.Flock
undefined: syscall.LOCK_EX
undefined: syscall.LOCK_NB
undefined: syscall.Flock
undefined: syscall.LOCK_UN
這是因?yàn)?Windows 系統(tǒng)不支持 pid 鎖,所以我們需要在 Linux 或 Mac 系統(tǒng)下才能正常運(yùn)行上面的程序。
上面代碼中演示了同時(shí)啟動(dòng) 10 個(gè) goroutinue,但在程序運(yùn)行過程中,只有一個(gè) goroutine 能獲得文件鎖(flock)。其它的 goroutinue 在獲取不到 flock 后,會(huì)拋出異常的信息。這樣即可達(dá)到同一文件在指定的周期內(nèi)只允許一個(gè)進(jìn)程訪問的效果。
代碼中文件鎖的具體調(diào)用:
syscall.Flock(int(f.Fd()), syscall.LOCK_EX|syscall.LOCK_NB)
我們采用了 syscall.LOCK_EX、syscall.LOCK_NB,這是什么意思呢?
flock 屬于建議性鎖,不具備強(qiáng)制性。一個(gè)進(jìn)程使用 flock 將文件鎖住,另一個(gè)進(jìn)程可以直接操作正在被鎖的文件,修改文件中的數(shù)據(jù),原因在于 flock 只是用于檢測文件是否被加鎖,針對文件已經(jīng)被加鎖,另一個(gè)進(jìn)程寫入數(shù)據(jù)的情況,內(nèi)核不會(huì)阻止這個(gè)進(jìn)程的寫入操作,也就是建議性鎖的內(nèi)核處理策略。
flock 主要三種操作類型:
- LOCK_SH:共享鎖,多個(gè)進(jìn)程可以使用同一把鎖,常被用作讀共享鎖;
- LOCK_EX:排他鎖,同時(shí)只允許一個(gè)進(jìn)程使用,常被用作寫鎖;
- LOCK_UN:釋放鎖。
進(jìn)程使用 flock 嘗試鎖文件時(shí),如果文件已經(jīng)被其他進(jìn)程鎖住,進(jìn)程會(huì)被阻塞直到鎖被釋放掉,或者在調(diào)用 flock 的時(shí)候,采用 LOCK_NB 參數(shù)。在嘗試鎖住該文件的時(shí)候,發(fā)現(xiàn)已經(jīng)被其他服務(wù)鎖住,會(huì)返回錯(cuò)誤,錯(cuò)誤碼為 EWOULDBLOCK。
flock 鎖的釋放非常具有特色,即可調(diào)用 LOCK_UN 參數(shù)來釋放文件鎖,也可以通過關(guān)閉 fd 的方式來釋放文件鎖(flock 的第一個(gè)參數(shù)是 fd),意味著 flock 會(huì)隨著進(jìn)程的關(guān)閉而被自動(dòng)釋放掉。
文章名稱:創(chuàng)新互聯(lián)GO教程:Go語言文件鎖操作
本文網(wǎng)址:http://www.5511xx.com/article/dhcippp.html


咨詢
建站咨詢
