溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

golang如何實(shí)現(xiàn)文件鎖

發(fā)布時間:2022-12-27 13:48:17 來源:億速云 閱讀:119 作者:iii 欄目:編程語言

本篇內(nèi)容主要講解“golang如何實(shí)現(xiàn)文件鎖”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“golang如何實(shí)現(xiàn)文件鎖”吧!

在golang中,可以利用sync包的api來實(shí)現(xiàn)文件鎖。文件鎖(flock)是對于整個文件的建議性鎖;也就是說,如果一個進(jìn)程在一個文件(inode)上放了鎖,其它進(jìn)程是可以知道的(建議性鎖不強(qiáng)求進(jìn)程遵守);文件鎖的調(diào)用語法“syscall.Flock(int(f.Fd()), syscall.LOCK_EX|syscall.LOCK_NB)”。

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

對于 flock,最常見的例子就是 Nginx,進(jìn)程運(yùn)行起來后就會把當(dāng)前的 PID 寫入這個文件,當(dāng)然如果這個文件已經(jīng)存在了,也就是前一個進(jìn)程還沒有退出,那么 Nginx 就不會重新啟動,所以 flock 還可以用來檢測進(jìn)程是否存在。

flock 是對于整個文件的建議性鎖。也就是說,如果一個進(jìn)程在一個文件(inode)上放了鎖,其它進(jìn)程是可以知道的(建議性鎖不強(qiáng)求進(jìn)程遵守)。最棒的一點(diǎn)是,它的第一個參數(shù)是文件描述符,在此文件描述符關(guān)閉時,鎖會自動釋放。而當(dāng)進(jìn)程終止時,所有的文件描述符均會被關(guān)閉。所以很多時候就不用考慮類似原子鎖解鎖的事情。

在具體介紹前,先上代碼

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)行上面的代碼會出現(xiàn)下面的錯誤:

golang如何實(shí)現(xiàn)文件鎖

這是因?yàn)?Windows 系統(tǒng)不支持 pid 鎖,所以我們需要在 Linux 或 Mac 系統(tǒng)下才能正常運(yùn)行上面的程序。

上面代碼中演示了同時啟動 10 個 goroutinue,但在程序運(yùn)行過程中,只有一個 goroutine 能獲得文件鎖(flock)。其它的 goroutinue 在獲取不到 flock 后,會拋出異常的信息。這樣即可達(dá)到同一文件在指定的周期內(nèi)只允許一個進(jìn)程訪問的效果。

代碼中文件鎖的具體調(diào)用:

syscall.Flock(int(f.Fd()), syscall.LOCK_EX|syscall.LOCK_NB)

我們采用了 syscall.LOCK_EX、syscall.LOCK_NB,這是什么意思呢?

flock 屬于建議性鎖,不具備強(qiáng)制性。一個進(jìn)程使用 flock 將文件鎖住,另一個進(jìn)程可以直接操作正在被鎖的文件,修改文件中的數(shù)據(jù),原因在于 flock 只是用于檢測文件是否被加鎖,針對文件已經(jīng)被加鎖,另一個進(jìn)程寫入數(shù)據(jù)的情況,內(nèi)核不會阻止這個進(jìn)程的寫入操作,也就是建議性鎖的內(nèi)核處理策略。

flock 主要三種操作類型:

  • LOCK_SH:共享鎖,多個進(jìn)程可以使用同一把鎖,常被用作讀共享鎖;

  • LOCK_EX:排他鎖,同時只允許一個進(jìn)程使用,常被用作寫鎖;

  • LOCK_UN:釋放鎖。

進(jìn)程使用 flock 嘗試鎖文件時,如果文件已經(jīng)被其他進(jìn)程鎖住,進(jìn)程會被阻塞直到鎖被釋放掉,或者在調(diào)用 flock 的時候,采用 LOCK_NB 參數(shù)。在嘗試鎖住該文件的時候,發(fā)現(xiàn)已經(jīng)被其他服務(wù)鎖住,會返回錯誤,錯誤碼為 EWOULDBLOCK。

flock 鎖的釋放非常具有特色,即可調(diào)用 LOCK_UN 參數(shù)來釋放文件鎖,也可以通過關(guān)閉 fd 的方式來釋放文件鎖(flock 的第一個參數(shù)是 fd),意味著 flock 會隨著進(jìn)程的關(guān)閉而被自動釋放掉。

到此,相信大家對“golang如何實(shí)現(xiàn)文件鎖”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI