Go语言flock文件锁的用法(附带实例)
当多个进程同时操作同一文件时,很容易导致文件中的数据混乱。这时要采用一些技术平衡这些冲突,文件锁(flock)就是这些技术之一。
flock 属于建议性锁,不具备强制性。一个进程使用 flock 将文件锁住,另一个进程可以直接操作已锁住的文件,修改文件中的数据。这是因为 flock 只是检测文件是否被加锁,即使一个文件已经加锁,但另一个进程仍要写入数据,内核也不会阻止这个进程的写入操作。这就是建议性锁的内核处理策略。
flock 主要有 3 种操作类型:
对于 flock,最常见的例子就是使用 Nginx。进程运行后把当前 PID 写入文件,如果文件已经存在,即前一个进程还没有退出,那么 Nginx 就不会重新启动,所以 flock 还可以检测进程是否存在。
因为 Windows 系统不支持 pid 锁,所以要在 Linux 或 Mac 系统下演示。
【实例】演示同时启动 10 个 goroutinue,但在程序运行过程中,只有一个 goroutine 能获得 flock,其他的 goroutinue 在获取不到 flock 后,抛出异常信息。
	
	
flock 属于建议性锁,不具备强制性。一个进程使用 flock 将文件锁住,另一个进程可以直接操作已锁住的文件,修改文件中的数据。这是因为 flock 只是检测文件是否被加锁,即使一个文件已经加锁,但另一个进程仍要写入数据,内核也不会阻止这个进程的写入操作。这就是建议性锁的内核处理策略。
flock 主要有 3 种操作类型:
- LOCK_SH:共享锁,多个进程可以使用同一把锁,常被用作读共享锁;
 - LOCK_EX:排他锁,同时只允许一个进程使用,常被用作写锁;
 - LOCK_UN:释放锁。
 
对于 flock,最常见的例子就是使用 Nginx。进程运行后把当前 PID 写入文件,如果文件已经存在,即前一个进程还没有退出,那么 Nginx 就不会重新启动,所以 flock 还可以检测进程是否存在。
因为 Windows 系统不支持 pid 锁,所以要在 Linux 或 Mac 系统下演示。
【实例】演示同时启动 10 个 goroutinue,但在程序运行过程中,只有一个 goroutine 能获得 flock,其他的 goroutinue 在获取不到 flock 后,抛出异常信息。
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 lock 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) {
            lock := New(locked_file)
            err := lock.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)
}
通过控制台打印的异常信息,即可得到同一文件在指定周期内只允许一个进程访问的结论。
 ICP备案:
 公安联网备案: