在我们对文件进行操作的时候, 如果你不需要你操作的文件被其他协程访问,则就需要使用一个文件锁来对我们操作的文件进行加锁,今天给大家推荐的这个gflock使用也非常简单:
首先安装依赖:
go get -u github.com/tekitian/gflock
使用示例
import "github.com/tekitian/gflock"
fileLock := gflock.New("/var/lock/go-lock.lock")
locked, err := fileLock.TryLock()
if err != nil {
// handle locking error
}
if locked {
// do work
fileLock.Unlock()
}
github仓库地址 https://github.com/tekintian/gflock
一个二次封装的文件/文件夹锁使用示例
filelock.go
package internal
import (
"fmt"
"log"
"os"
"path/filepath"
"github.com/tekitian/gflock"
)
// FileLock provides a file lock mechanism based on gflock.
type FileLock struct {
lock *gflock.GFlock
verbose bool
}
// NewFileLock creates a new instance of FileLock.
func NewFileLock(path string, verbose bool) (*FileLock, error) {
err := os.MkdirAll(filepath.Dir(path), 0o750)
if err != nil {
return nil, fmt.Errorf("creating lock file directory: %w", err)
}
if verbose {
log.Printf("Initializing file lock at %s", path)
}
return &FileLock{
lock: flock.New(path),
verbose: verbose,
}, nil
}
// Release unlocks the file lock.
func (f *FileLock) Release() error {
if err := f.lock.Unlock(); err != nil {
return fmt.Errorf("releasing file lock at %s: %w", f.lock.Path(), err)
}
if f.verbose {
log.Printf("Lock file %s successfully released", f.lock.Path())
}
return nil
}
// Acquire tries to acquire a file lock.
// It is possible for multiple goroutines within the same process
// to acquire the same lock, so acquireLock is not thread safe in
// that sense, but protects access across different processes.
func (f *FileLock) Acquire() error {
ok, err := f.lock.TryLock()
if err != nil {
return fmt.Errorf("acquiring file lock at %s: %w", f.lock.Path(), err)
}
if !ok {
return fmt.Errorf("lock %s already acquired by another process", f.lock.Path())
}
if f.verbose {
log.Printf("Acquired lock file at %s", f.lock.Path())
}
return nil
}
测试用例
需要安装增强测试包 got get github.com/stretchr/testify
filelock_test.go
package internal
import (
"path/filepath"
"testing"
"github.com/stretchr/testify/require"
)
// TestAcquireFileLock tests that a lock can be acquired multile times
// within a same process.
func TestAcquireFileLock(t *testing.T) {
tempDir := t.TempDir()
fl, err := NewFileLock(filepath.Join(tempDir, ".myapp.lock"), false)
require.NoError(t, err)
defer func() {
err := fl.Release()
require.NoError(t, err)
}()
// acquire lock
err = fl.Acquire()
require.NoError(t, err)
require.True(t, fl.lock.Locked())
// acquiring lock a second time within the same process
// should succeed
err = fl.Acquire()
require.NoError(t, err)
require.True(t, fl.lock.Locked())
// release lock
err = fl.Release()
require.NoError(t, err)
require.False(t, fl.lock.Locked())
// acquire a released lock
err = fl.Acquire()
require.NoError(t, err)
require.True(t, fl.lock.Locked())
}