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备案:
公安联网备案: