Restreindre à l’instance unique de l’exécutable avec Golang

Je dois autoriser une seule instance de mon exécutable Golang à la fois. Je ne sais pas comment utiliser un Global Mutex pour s’assurer qu’aucune autre instance ne fonctionne.

Cela fonctionnerait sur une machine Windows.

Je sais que ce sujet est un peu ancien, mais j’en avais besoin récemment sous Windows et je posterais ici comment je l’ai fait au cas où quelqu’un d’autre en aurait besoin.

Merci à @VonC pour m’avoir orienté dans la bonne direction.

var ( kernel32 = syscall.NewLazyDLL("kernel32.dll") procCreateMutex = kernel32.NewProc("CreateMutexW") ) func CreateMutex(name ssortingng) (uintptr, error) { ret, _, err := procCreateMutex.Call( 0, 0, uintptr(unsafe.Pointer(syscall.SsortingngToUTF16Ptr(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") 

J’ai créé une lib avec un exemple plus complet: https://github.com/rodolfoag/gow32

THX!

Il ne semble pas y avoir de solution multi-plateforme (à part l’écriture d’un fichier et la recherche de ce fichier au début).

Sous Windows, ce thread rapporte

l’approche recommandée (et celle qui a bien fonctionné pour moi) est d’utiliser la fonction CreateSemaphore .
Si le nom que vous spécifiez commence par ” Global\ “, le sémaphore est unique pour tout le système et une seconde tentative pour l’ouvrir échouera.

Ceci est un appel kernel32, qui contient un wrapper dans Go disponible .

Kostix ajoute dans les commentaires:

regardez le code source de Go autour de la hiérarchie pkg \ syscall – il contient une bonne quantité d’exemples sur la façon d’appeler des DLL sous Windows en utilisant syscalls (et c’est comment vous accédez à tout dans l’API Windows).

Ce serait syscall/dll_windows.go . (Et voici un résumé )

Le paquetage odbc de brainman est un autre exemple d’appels directs d’API sous Windows – peut-être plus facile à digérer.

Comme api/zapi_windows.go .

Vous pouvez utiliser des sockets, simples à utiliser et fonctionnant vraiment sur tout.

 package main import ( "fmt" "net" "os" "ssortingngs" ) const ( INSTANCE_PORT = 9292 ) func main() { listener, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", INSTANCE_PORT)) if err != nil { if ssortingngs.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) } } 

Vous pouvez adapter le code de la source de la bibliothèque python de tendo

ce qu’ils font, c’est pour les fenêtres:

créer un fichier constitué du chemin absolu exécutable (enfin c’est une bibliothèque, donc dans votre cas, vous pouvez simplement définir un identifiant, pour vous empêcher de “mettre l’exécutable à 2 endroits”)

  • Pour Windows: essayez d’abord de supprimer le fichier s’il existe et si vous ne créez pas le fichier avec os.O_CREAT | os.O_EXCL | os.O_RDWR os.O_CREAT | os.O_EXCL | os.O_RDWR
  • Pour les systèmes compatibles POSIX: essayez d’abord de supprimer le fichier s’il existe et, si ce n’est pas le cas, créez le fichier et fcntl.LOCK_EX | fcntl.LOCK_NB un verrou à l’aide de fcntl.LOCK_EX | fcntl.LOCK_NB fcntl.LOCK_EX | fcntl.LOCK_NB

tout échec signifie que le programme est déjà en cours d’exécution

et puis vous pouvez utiliser une action différée pour supprimer le verrou (sur le système posix) et supprimer le fichier

Aller vous permettre de créer les deux versions avec un commentaire de construction pour dire quel fichier comstackr en fonction de votre système d’exploitation afin que vous ayez

pour le système unix

 // +build !windows package main import ( "os" "syscall" ) func create_lock_file(filename ssortingng) (*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 } 

Pour les fenêtres:

 // +build !windows package main import ( "os" ) func create_lock_file(filename ssortingng) (*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) } 

et un test

 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 ") } 

J’ai commencé une bibliothèque à partir de celle que vous pouvez trouver ici