首頁 > 後端開發 > Golang > 主體

golang怎麼實作文件鎖

青灯夜游
發布: 2022-12-19 11:08:18
原創
4925 人瀏覽過

在golang中,可以利用sync套件的api來實作檔案鎖定。文件鎖(flock)是對於整個文件的建議性鎖;也就是說,如果一個進程在一個文件(inode)上放了鎖,其它進程是可以知道的(建議性鎖不強求進程遵守);文件鎖的呼叫語法「syscall.Flock(int(f.Fd()), syscall.LOCK_EX|syscall.LOCK_NB)」。

golang怎麼實作文件鎖

本教學操作環境: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 系統下執行上面的程式碼會出現下面的錯誤:

golang怎麼實作文件鎖

##這是因為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怎麼實作文件鎖的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!