golang文件锁

在程序并发运行时,有时会限制多个线程操作同一个文件,这是就需要文件锁,类似于线程中的锁。不同的系统平台有不同的实现,这里以Linux为例。

先来说一下锁的集中情况,在go语言的syscall包中定义了下面几个常量

LOCK_EX    = 0x2
LOCK_NB    = 0x4
LOCK_SH    = 0x1
LOCK_UN    = 0x8
  1. LOCK_EX指排他锁,也就是同时只允许一个线程使用
  2. LOCK_NB指其他线程遇到一个排他锁会直接返回error,而不加该参数时线程会等待锁释放,利用这个参数可以简单的检测一个文件是否被占用
  3. LOCK_SH指共享锁,多个线程都可以使用
  4. LOCK_UN指释放一个锁

而在go语言中对一个文件锁的操作主要借助syscall的Flock方法

func Flock(fd int, how int) (err error) {
	_, _, e1 := Syscall(SYS_FLOCK, uintptr(fd), uintptr(how), 0)
	if e1 != 0 {
		err = errnoErr(e1)
	}
	return
}

这里我们只要传入文件标识符fd和锁的操作参数how即可,如:

f, err := os.OpenFile(fileName, os.O_RDWR|os.O_CREATE, 0644)
syscall.Flock(int(l.f.Fd()), syscall.LOCK_EX|syscall.LOCK_NB)

由于对于不同平台有不同实现,上面只适用于linux,为了解决各种平台的适配,在Prometheus的tsdb中有一套文件锁的实现,可以直接拿过来用或参考其相关实现。

题图来自unsplash:https://unsplash.com/photos/sUIrV6z9JCs