// Handle pid file based locking.
package lockfile
import (
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"syscall"
)
type Lockfile string
var (
ErrBusy = errors.New("Locked by other process") // If you get this, retry after a short sleep might help
ErrNeedAbsPath = errors.New("Lockfiles must be given as absolute path names")
ErrInvalidPid = errors.New("Lockfile contains invalid pid for system")
ErrDeadOwner = errors.New("Lockfile contains pid of process not existent on this system anymore")
)
// Describe a new filename located at path. It is expected to be an absolute path
func New(path string) (Lockfile, error) {
if !filepath.IsAbs(path) {
return Lockfile(""), ErrNeedAbsPath
}
return Lockfile(path), nil
}
// Who owns the lockfile?
func (l Lockfile) GetOwner() (*os.Process, error) {
name := string(l)
// Ok, see, if we have a stale lockfile here
content, err := ioutil.ReadFile(name)
if err != nil {
return nil, err
}
var pid int
_, err = fmt.Sscanln(string(content), &pid)
if err != nil {
return nil, ErrInvalidPid
}
// try hard for pids. If no pid, the lockfile is junk anyway and we delete it.
if pid > 0 {
p, err := os.FindProcess(pid)
if err != nil {
return nil, err
}
err = p.Signal(os.Signal(syscall.Signal(0)))
if err == nil {
return p, nil
}
errno, ok := err.(syscall.Errno)
if !ok {
return nil, err
}
switch errno {
case syscall.ESRCH:
return nil, ErrDeadOwner
case syscall.EPERM:
return p, nil
default:
return nil, err
}
} else {
return nil, ErrInvalidPid
}
panic("Not reached")
}
// Try to get Lockfile lock. Returns nil, if successful and and error describing the reason, it didn't work out.
// Please note, that existing lockfiles containing pids of dead processes and lockfiles containing no pid at all
// are deleted.
func (l Lockfile) TryLock() error {
name := string(l)
// This has been checked by New already. If we trigger here,
// the caller didn't use New and re-implemented it's functionality badly.
// So panic, that he might find this easily during testing.
if !filepath.IsAbs(string(name)) {
panic(ErrNeedAbsPath)
}
tmplock, err := ioutil.TempFile(filepath.Dir(name), "")
if err != nil {
return err
} else {
defer tmplock.Close()
defer os.Remove(tmplock.Name())
}
_, err = tmplock.WriteString(fmt.Sprintf("%d\n", os.Getpid()))
if err != nil {
return err
}
// return value intentionally ignored, as ignoring it is part of the algorithm
_ = os.Link(tmplock.Name(), name)
fiTmp, err := os.Lstat(tmplock.Name())
if err != nil {
return err
}
fiLock, err := os.Lstat(name)
if err != nil {
return err
}
// Success
if os.SameFile(fiTmp, fiLock) {
return nil
}
_, err = l.GetOwner()
switch err {
default:
// Other errors -> defensively fail and let caller handle this
return err
case nil:
return ErrBusy
case ErrDeadOwner, ErrInvalidPid:
// cases we can fix below
}
// clean stale/invalid lockfile
err = os.Remove(name)
if err != nil {
return err
}
// now that we cleaned up the stale lockfile, let's recurse
return l.TryLock()
}
// Release a lock again. Returns any error that happend during release of lock.
func (l Lockfile) Unlock() error {
return os.Remove(string(l))
}
使用windows c++ LockFIle() 锁定文件然后从中获取流?
【中文标题】使用windows c++ LockFIle() 锁定文件然后从中获取流?【英文标题】:Lock a file using windows c++ LockFIle() then get a stream from it?【发布时间】:2014-07-09 21:24:38【问题描述】:
我已经使用LockFileEx 锁定了一个文件,但我无法从中打开一个流。
HANDLE indexHandle = CreateFile (indexFileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, 0,
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0);
bool indexLock = false;
OVERLAPPED overlapped;
memset (&overlapped, 0, sizeof (overlapped));
while (noOfTries >0 && !indexLock)
if (!LockFileEx (indexHandle, LOCKFILE_EXCLUSIVE_LOCK, 0, 0, UINT_MAX, &overlapped))
InfoLog << "Failed to get lock on index file -- Error code is ["
<< GetLastError () <<"]"<<std::endl;
Sleep(sleepTime);
noOfTries--;
else
indexLock=true;
获取锁后,我想这样做:
string indexFile = mPath + Util::PATH_SEPARATOR + mIndexFileName;
os.open( indexFile.c_str(), ios_base::app);
if (!os)
InfoLog << "BinaryFileSystemObjectStore:: ofstream: Failed to open index for write: " << indexFile.c_str() << endl;