在Go中实现信号量的最佳方法是什么?

时间:2013-09-24 17:01:23

标签: go semaphore

我有一个测试程序,我想从命令行运行程序的多个副本,我需要知道要启动的程序的第一个实例。在达特,我做了以下有人向我建议的事情:

RawServerSocket.bind("127.0.0.1", 8087)

如果失败,那么我知道另一个程序已“锁定”该端口。这对我来说足以解决问题。程序终止或明确关闭套接字时释放锁。

如何在Go中获得类似的结果?

3 个答案:

答案 0 :(得分:3)

'unix方式'是在/var/run/<name>.pid中创建一个pid文件 我们就是这样做的Docker https://github.com/dotcloud/docker/blob/master/docker/docker.go#L91 如果该文件存在,则表示该程序已经启动。

我不建议使用bind方法,它只是没有锁定端口,你不能确定其他程序没有使用该端口。

答案 1 :(得分:3)

您没有说您正在使用哪个平台。如果您想跨平台,那么打开本地套接字的解决方案非常简单。以下是Go中的操作方法。

package main

import (
    "log"
    "net"
    "time"
)

func main() {
    ln, err := net.Listen("tcp", "127.0.0.1:9876")
    if err != nil {
        log.Fatal("Failed to get lock: ", err)
    }
    defer ln.Close()
    log.Print("Started")
    time.Sleep(time.Second * 10)
    log.Print("Ending")
}

不幸的是,在不使用套接字的情况下执行此操作的跨平台方法非常困难,并且涉及两组代码,一组用于Unix系统,一组用于Windows。

请注意,病毒检查程序不喜欢在Windows上打开侦听套接字的程序...

答案 2 :(得分:2)

如果将os.OpenFile()os.CREATE | os.O_EXCL标志一起使用呢?

file, err := os.OpenFile("lock", os.O_CREATE | os.O_EXCL | os.O_RDWR, 0400)
if err != nil {
        // Someone else has acquired the lock.
}
defer file.Close()
defer os.Remove("lock") // Ignoring errors here!

我没有编译或测试过这个,但是它应该可以工作,无论如何,你明白了......