六安市网站建设,做淘宝客网站要申请什么,安徽网络推广新手,wordpress 动漫主题先说结论
1. golang提供了syscall包来实现文件/目录的加锁#xff0c;解锁
2. syscall包属于文件锁#xff0c;是比较底层的技术#xff0c;并不能在所有操作系统上完全实现#xff0c;linux上实现了#xff0c;windows下面就没有
3. 加锁时调用syscall.Flock(fd#…先说结论
1. golang提供了syscall包来实现文件/目录的加锁解锁
2. syscall包属于文件锁是比较底层的技术并不能在所有操作系统上完全实现linux上实现了windows下面就没有
3. 加锁时调用syscall.Flock(fdsyscall.LOCK_EX)解锁时调用syscall.Flock(fd, syscall.LOCK_UN)
4. 加锁成功后对加锁的文件fd进行Close()操作同样会释放锁切记
代码实现
锁的定义如下内部两个变量文件/目录的全路径名文件对象 // 文件锁/目录锁 type DirLock struct { dir string // 文件/目录的全路径名 f *os.File // 文件对象 } 加锁的实现
核心代码是 syscall.Flock(int(f.Fd()), LOCK_EX|syscall.LOCK_NB)注意其中的标记
LOCK_EX 加锁标记。只有一个进程能加锁成功其他进程再尝试加锁时会阻塞等同于我们常用的写锁
LOCK_NB 不阻塞标记。如果其他进程已加锁成功自己去尝试加锁时就不再阻塞而是直接返回错误 // 加锁 func (l *DirLock) 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 err } return nil } 解锁的实现
核心代码是 syscall.Flock(int(l.f.Fd()), syscall.LOCK_UN)
LOCK_UN 解锁标记。如果自己已经加锁成功可以用此标记去解锁 // 解锁 func (l *DirLock) Unlock() error { defer l.f.Close() // 关闭文件 return syscall.Flock(int(l.f.Fd()), syscall.LOCK_UN) // LOCK_UN表解锁 } 实验
我们建立5个协程每秒去尝试加锁一次失败则1秒后重试成功则持续2秒后解锁
核心代码如下 // 5个协程都尝试对目录加锁加锁失败的就重试加锁成功的2秒后释放 for i : 0; i 5; i { wg.Add(1) go func(num int) { dirLock : New(dir) ticker : time.NewTicker(time.Second) // 定时器每秒尝试1次 for { select { case -ticker.C: { err : dirLock.Lock() // 加锁尝试 if err ! nil { fmt.Printf(lock dir failed, goroutine num%d, err%s \n, num, err.Error()) continue } fmt.Println(lock dir succeed, goroutine num, num) goto end } } } end: time.Sleep(time.Second*2) dirLock.Unlock() // 解锁 wg.Done() }(i) } wg.Wait() 实验结果如下图 完整代码
package main
import (fmtossyncsyscalltime
)// 目录锁
type DirLock struct {dir string // 目录的全路径名f *os.File // 文件对象
}func New(dir string) *DirLock {return DirLock{dir: dir,}
}// 加锁
func (l *DirLock) Lock() error {f, err : os.Open(l.dir)if err ! nil {return err}l.f ferr syscall.Flock(int(f.Fd()), syscall.LOCK_EX|syscall.LOCK_NB)if err ! nil {return err}return nil
}// 释放锁
func (l *DirLock) Unlock() error {defer l.f.Close() // 其实不执行Close()也会释放目录锁return syscall.Flock(int(l.f.Fd()), syscall.LOCK_UN)
}func main() {dir, _ : os.Getwd()wg : sync.WaitGroup{}// 5个协程都尝试对目录加锁加锁失败的就重试加锁成功的2秒后释放for i : 0; i 5; i {wg.Add(1)go func(num int) {dirLock : New(dir)ticker : time.NewTicker(time.Second) // 定时器每秒尝试1次for {select {case -ticker.C:{err : dirLock.Lock() // 加锁尝试if err ! nil {fmt.Printf(lock dir failed, goroutine num%d, err%s \n, num, err.Error())continue}fmt.Println(lock dir succeed, goroutine num, num)goto end}}}end:time.Sleep(time.Second*2)dirLock.Unlock() // 解锁wg.Done()}(i)}wg.Wait()
}