我需要一次只允许一个Golang可执行文件的实例。我不确定如何使用Global Mutex来确保没有其他实例正在运行。
这将在Windows机器上运行。
答案 0 :(得分:7)
似乎不是一个跨平台的解决方案(除了编写文件,并在开始时查找该文件)。
在Windows上,这是thread reports
推荐的方法(以及对我有用的方法)是使用
CreateSemaphore
function 如果您指定的名称以"Global\
"开头,那么信号量对于整个系统是唯一的,第二次尝试打开它将失败。
这是一个kernel32调用,它有一些wrapper in Go available。
kostix在评论中添加:
查看围绕pkg \ syscall层次结构的Go源代码 - 它包含大量关于如何使用系统调用在Windows上调用DLL的示例(以及如何在Windows API中访问任何内容)
那将是syscall/dll_windows.go
。 (这里is a gist)
odbc package by brainman是Windows上直接API调用的另一个示例 - 可能更容易理解。
答案 1 :(得分:4)
我知道这个主题有点陈旧,但我最近在Windows上需要它,我会在这里发布我是如何做到的,以防其他人需要。
向@VonC求助,指出我正确的方向。
var (
kernel32 = syscall.NewLazyDLL("kernel32.dll")
procCreateMutex = kernel32.NewProc("CreateMutexW")
)
func CreateMutex(name string) (uintptr, error) {
ret, _, err := procCreateMutex.Call(
0,
0,
uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(name))),
)
switch int(err.(syscall.Errno)) {
case 0:
return ret, nil
default:
return ret, err
}
}
// mutexName starting with "Global\" will work across all user sessions
_, err := CreateMutex("SomeMutexName")
我使用更完整的示例创建了一个lib:https://github.com/rodolfoag/gow32
THX!
答案 2 :(得分:3)
您可以使用简单易用的套接字,并且可以真正处理所有内容。
package main
import (
"fmt"
"net"
"os"
"strings"
)
const (
INSTANCE_PORT = 9292
)
func main() {
listener, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", INSTANCE_PORT))
if err != nil {
if strings.Index(err.Error(), "in use") != -1 {
//optionally send command line arguments to the other instance
fmt.Fprintln(os.Stderr, "Already running.")
return
} else {
panic(err)
}
}
for {
conn, err := listener.Accept()
if err != nil {
println("Error accept:", err.Error())
return
}
go do_something_with(conn)
}
}
答案 3 :(得分:2)
您可以调整tendo的python库source
中的代码 他们做的是什么 对于Windows:创建一个由可执行的绝对路径构成的文件(好吧它是一个库,所以在你的情况下,你可以只定义一个标识符,以防止你"我把可执行文件放在2个地方&#34 ;)
os.O_CREAT | os.O_EXCL | os.O_RDWR
fcntl.LOCK_EX | fcntl.LOCK_NB
获取锁定任何失败都意味着程序已在运行
然后您可以使用延迟操作来删除锁定(在posix系统上)并删除文件
Go允许您创建带有构建注释的版本,以根据您的操作系统告知要编译哪个文件,以便
用于unix系统
// +build !windows
package main
import (
"os"
"syscall"
)
func create_lock_file(filename string) (*os.File, error) {
file, err := os.OpenFile(filename, os.O_WRONLY, 0666)
if err != nil {
return nil, err
}
err = syscall.Flock(int(file.Fd()), syscall.LOCK_EX|syscall.LOCK_NB)
if err != nil {
return nil, err
}
return file, nil
}
for windows:
// +build !windows
package main
import (
"os"
)
func create_lock_file(filename string) (*os.File, error) {
if _, err := os.Stat(filename); err == nil {
err = os.Remove(filename)
if err != nil {
return nil, err
}
}
return os.OpenFile(filename, os.O_CREATE|os.O_EXCL|os.O_RDWR, 0666)
}
和测试
package main
import (
"fmt"
"time"
)
func main() {
_, err := create_lock_file("plop.lock")
if err != nil {
fmt.Println("error ", err.Error())
}
time.Sleep(10 * time.Second)
fmt.Println("end ")
}
我已经从中创建了一个库that you can find here