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("ディレクトリ%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("出力:%d\n"、num)
            wg.Done()
        }(i)
    }
    wg.Wait()
    time.Sleep(2*time.Second)

} 

Windows で上記のコードを実行すると、次のエラーが発生します。

undefined: syscall.Flock
undefined: syscall.LOCK_EX
undefined: syscall.LOCK_NB
undefined: syscall.Flock
undefined: syscall.LOCK_UN

これは、Windows システムが PID ロックをサポートしていないためで、上記のプログラムを Linux または Mac システムで通常どおり実行する必要があります。

上記のコードは、10 個のゴルーチンが同時に開始されることを示していますが、プログラムの実行中にファイル ロック (flock) を取得できるゴルーチンは 1 つだけです。他の goroutine は、flock を取得できなかった場合に例外情報をスローします。これにより、指定期間内に同一ファイルへのアクセスを1つのプロセスのみに許可する効果が得られる。

コード日本語ロックの具体的な呼び出し:

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

syscall.LOCK_EX、syscall.LOCK_NB を使用しましたが、これは何を意味しますか?

flock は推奨ロックであり、必須ではありません。 1 つのプロセスは flock を使用してファイルをロックし、別のプロセスはロックされたファイルを直接操作してファイル内のデータを変更できます。その理由は、flock はファイルがロックされているかどうかを検出するためにのみ使用されるためです。ロックされているファイルについては、別のプロセス データを書き込む場合、カーネルはこのプロセスの書き込み操作を妨げません。これは、勧告ロックのカーネル処理戦略です。

flock には主に 3 種類の操作があります。

  • LOCK_SH: 共有ロック。複数のプロセスが同じロックを使用でき、読み取り共有ロックとしてよく使用されます。
  • LOCK_EX: 排他的ロック。同時に 1 つのプロセスのみが使用を許可され、書き込みロックとしてよく使用されます。
  • LOCK_UN: ロックを解除します。

プロセスが flock を使用してファイルをロックしようとしたとき、そのファイルが別のプロセスによってすでにロックされている場合、プロセスはロックが解放されるまで、または LOCK_NB パラメーターを使用して flock が呼び出されるまでブロックされます。ファイルをロックしようとすると、他のサービスによってロックされていることがわかり、エラー コード EWOULDBLOCK でエラーが返されます。

flock ロックの解放は非常に特徴的で、LOCK_UN パラメータを呼び出してファイル ロックを解放することも、fd (flock の最初のパラメータは fd) を閉じることでファイル ロックを解放することもできます。プロセスが閉じられ、自動的に解放されます。

 

「 Go言語のファイルロック操作」についてわかりやすく解説!絶対に観るべきベスト2動画

【たった1時間で学べる】Go言語のプログラミング初心者向けの超入門講座【文字書き起こし、ソースコードも完全無料!】
【初心者必見!】Go言語とは?できることや学ぶメリット・将来性について解説

Share via
Copy link