github.com/keysonZZZ/kmg@v0.0.0-20151121023212-05317bfd7d39/kmgProcessMutex/mutex.go (about)

     1  // +build linux darwin
     2  
     3  package kmgProcessMutex
     4  
     5  import (
     6  	"github.com/bronze1man/kmg/kmgErr"
     7  	"os"
     8  	"path/filepath"
     9  	"syscall"
    10  )
    11  
    12  type FileMutex struct {
    13  	isOwner  bool
    14  	filePath string
    15  	Name     string
    16  	f        *os.File
    17  }
    18  
    19  // flock 加锁,会将锁(系统级别)挂在某个文件上,只要有进程给某个文件挂上了锁,则其他进程(包括本进程)就必须解锁
    20  func (fm *FileMutex) Lock() {
    21  	kmgErr.PanicIfError(syscall.Flock(int(fm.getFd()), int(syscall.LOCK_EX)))
    22  }
    23  
    24  // flock 加的锁,有两种方式解除锁:
    25  // 1.加锁的进程退出了,锁自动释放
    26  // 2.在进程内,使用 fd0 挂上的锁,显式的使用 fd0 解锁;
    27  // 注意:同一个进程内,fd0 和 fd1 指向同一个文件(fd1 不是 fd0 的副本),若是 fd0 挂上的锁,必须用 fd0 来解锁,fd1 无法解锁
    28  func (fm *FileMutex) UnLock() {
    29  	kmgErr.PanicIfError(syscall.Flock(fm.getFd(), int(syscall.LOCK_UN)))
    30  }
    31  
    32  func (fm *FileMutex) getFd() int {
    33  	if fm.f != nil {
    34  		return int(fm.f.Fd())
    35  	}
    36  	if fm.Name == "" {
    37  		panic(`no specialed file [Name] for locking,Example:l := &kmgProcessMutex.FileMutex{Name: "abc"}`)
    38  	}
    39  	fm.filePath = filepath.Join("/tmp", fm.Name)
    40  	var err error
    41  	fm.f, err = os.OpenFile(fm.filePath, os.O_CREATE|os.O_EXCL, os.FileMode(0777))
    42  	if err == nil {
    43  		return int(fm.f.Fd())
    44  	}
    45  	if os.IsExist(err) {
    46  		fm.f, err = os.OpenFile(fm.filePath, os.O_RDONLY, os.FileMode(0777))
    47  	} else {
    48  		kmgErr.LogErrorWithStack(err)
    49  	}
    50  	return int(fm.f.Fd())
    51  }