flock 是建议性锁,不具备强制性。进程在文件(inode)放了锁,其他进程可以知道。如果有进程不讲武德,不判断锁的存在,直接进行文件件操作也是允许的。

flock 常用于文件数据竞争管理,也会用来检测进程是否存在(进程终止,锁自动释放)。

主要三种操作类型:

  • LOCK_SH,共享锁,多个进程可以使用同一把锁,常被用作读共享锁;
  • LOCK_EX,排他锁,同时只允许一个进程使用,常被用作写锁;
  • LOCK_UN,释放锁;

LOCK_NB 参数,在获取锁失败,不会等待,立即返回错误。

下面用 Go 验证 flock

注意:Windows 不支持 pid 锁。

flock1.go

func main() {
        var f = "app.log"
        file, err := os.OpenFile(f, os.O_RDWR, os.ModeExclusive)
        if err != nil {
                panic(err)
        }
        defer file.Close()

        // 调用系统调用加锁
        err = syscall.Flock(int(file.Fd()), syscall.LOCK_EX|syscall.LOCK_NB)
        if err != nil {
                panic(err)
        }
        defer syscall.Flock(int(file.Fd()), syscall.LOCK_UN)
        // 读取文件内容
        all, err := ioutil.ReadAll(file)
        if err != nil {
                panic(err)
        }

        fmt.Printf("%s", all)
        time.Sleep(time.Second * 10) //模拟耗时操作
}

运行:

go run flock1.go

查看锁

$ lslocks
可以看到 app.log 锁已经加上了

flock1            895  FLOCK   5B WRITE 0     0   0 /data/go-workspace/test/app.log

再次运行 flock1.go

报错资源暂时不可用

panic: resource temporarily unavailable

goroutine 1 [running]:
main.main()
	/data/go-workspace/test/flock1.go:22 +0x2d6
exit status 2

参考