Какой лучший способ реализовать семафор в Go
У меня есть тестовая программа, в которой я хочу запустить несколько копий программы из командной строки, и мне нужно знать первый экземпляр программы для запуска. В Dart я делаю следующее, что мне кто-то предложил:
RawServerSocket.bind("127.0.0.1", 8087)
Если это не удается, то я знаю, что другая программа "заблокировала" порт. Это решает проблему достаточно хорошо для меня. Блокировка снимается, когда программа завершается или когда сокет явно закрыт.
Как я могу достичь аналогичного результата в Go?
4 ответа
Вы не говорите, какую платформу вы используете. Если вы хотите быть кроссплатформенным, то решение открытия локального сокета очень простое. Вот как вы делаете это в 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...
"Unix-способ" заключается в создании pid-файла в /var/run/
Я не рекомендовал бы использовать метод bind, он блокирует порт даром, и вы не можете быть уверены, что другая программа не использует этот порт.
Как насчет использования 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!
Я не компилировал и не проверял это, но он должен работать, и в любом случае, вы поняли...
Использоватьgithub.com/gofrs/flock
package, используя примерно такой код для ваших целей:
import "github.com/gofrs/flock"
fileLock := flock.New("/var/lock/go-lock.lock")
locked, err := fileLock.TryLock()
if err != nil {
// handle locking error
}
if locked {
// handle "first one in" case
fileLock.Unlock()
} else {
// handle subsequent cases
}
Для получения дополнительной информации см. https://github.com/gofrs/flock .