golang Lockfile使用PID文件

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了golang Lockfile使用PID文件相关的知识,希望对你有一定的参考价值。

// 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;

我这样做是因为我发现逐行阅读流更容易...

有解决办法吗?

【问题讨论】:

【参考方案1】:

来自documentation for LockFileEx:

如果锁定进程再次打开文件,它无法通过第二个句柄访问指定区域,直到它解锁该区域。

因此,您需要使用已有的句柄,而不是创建新的句柄。

_open_osfhandle 函数允许您从现有句柄创建文件描述符,然后您可以将此文件描述符传递给 ofstream constructor 而不是文件名。

【讨论】:

ofstream 构造函数不接受文件描述符作为构造函数参数......你能帮我吗? 自 VS6 以来这似乎已经改变,不再受支持。这是不幸的;我不知道为什么我们失去了这些基本功能。也许answers to this question 可能会有所帮助。【参考方案2】:

您使用FILE_SHARE_READ 打开文件。这意味着您允许进一步以只读方式打开文件。然后你尝试打开它写,会失败。

请改用FILE_SHARE_READ | FILE_SHARE_WRITE

【讨论】:

以上是关于golang Lockfile使用PID文件的主要内容,如果未能解决你的问题,请参考以下文章

异常lockfile.AlreadyLocked: ~/airflow/airflow-scheduler.pid is already locked

lockfile-create 在 bash 脚本中不起作用

yum lockfile is held by another process

使用windows c++ LockFIle() 锁定文件然后从中获取流?

读写两个进程的同一个文件是不是需要lockfile

Delphi 在 Windows 7 64 上使用 LockFile