2014-04-18 2 views
5

한 번에 하나의 Golang 인스턴스 만 허용하면됩니다. Global Mutex를 사용하여 다른 인스턴스가 실행되지 않도록하는 방법을 잘 모르겠습니다.Golang을 사용하여 실행 파일의 단일 인스턴스로 제한

이것은 Windows 컴퓨터에서 실행됩니다.

+0

https://groups.google.com/forum/#!topic/golang-nuts/tBEh_eGl8jY –

+0

새 승인 된 답변에 대한 좋은 선택 :) – VonC

답변

2

나는이 주제가 약간 낡았다는 것을 알고 있지만, 나는 최근에 Windows에서 그것을 필요로했으며 다른 누군가가 필요로 할 때 어떻게했는지 게시 할 것이다.

올바른 방향으로 나를 가리키는 @VonC에 대한 Thx. https://github.com/rodolfoag/gow32

들으 :

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 디렉토리를 만들어!

+0

잘 했어. +1 – VonC

7

크로스 플랫폼 솔루션 (파일을 쓰고 시작 시간에 해당 파일을 찾는 것)이 아닌 것 같습니다. Windows에서

thread reports

권장되는 방법 (나를 위해 큰 일을 한 일)을 CreateSemaphore function을 사용하는 것입니다.
지정한 이름이 "Global\"으로 시작하면 세마포어는 전체 시스템에서 고유하며 두 번째 시도는 실패합니다.

이 메시지는 kernel32 호출이며, 일부는 wrapper in Go available입니다. 이 시스템 콜을 사용하여 Windows에 DLL이를 호출하는 방법에 대한 예제의 좋은 재산을 포함 (그리고 - pkg 부 \의 콜 계층 구조의 주위에 이동 소스 코드를

모습 :

kostix

은 코멘트 추가 Windows API에서 액세스하는 방법입니다.)

그러면 syscall/dll_windows.go이됩니다. 소화가 가능 쉽게 - (그리고 여기 is a gist)

odbc package by brainman Windows에서 직접 API 호출의 또 다른 예입니다.

마찬가지로 api/zapi_windows.go.

+0

래퍼에서 함수 호출이 표시되지 않습니다. 아마도 완전하지는 않습니까? –

+0

@KevinPostal 네, 완료되지 않았습니다. 그냥 Go에서 win dll을 호출하는 것이 가능한지 예제로 언급했습니다. – VonC

+1

@KevinPostal,'pkg \ syscall' 계층 구조에 대한 Go 소스 코드를 살펴보십시오. - syscalls를 사용하여 Windows에서 DLL을 호출하는 방법에 대한 많은 예제가 포함되어 있습니다 (Windows API에서 액세스하는 방법). brainman이 만든 'odbc' 패키지는 [Windows에서의 직접 API 호출] (https://code.google.com/p/odbc/source/browse/api/zapi_windows.go)의 또 다른 예입니다. 아마도 더 쉽게 소화 할 수 있습니다. – kostix

2

소켓을 사용하면 간단하고 사용하기 쉽고 모든 것을 실제로 처리 할 수 ​​있습니다.

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) 
    } 
} 
+0

이 방법을 고려하고있었습니다. 잠재적으로 사용하지 않을 포트를 사용하기 란 쉽지 않습니다. –

+0

첫 번째로 제공되는 임시 포트 범위가 있습니다. http://en.wikipedia.org/wiki/Ephemeral_port –

+2

임시 포트가 작동하지 않습니다. 다음 인스턴스는 다른 포트를 가져 와서 청취 할 수 있습니다. – siritinga

2

당신은 텐도의 파이썬 라이브러리의 코드를 적용 할 수는 source

그들이 할 것은 창문 입니다 :

가 실행 절대 경로로 만들어진 파일을 생성 (잘은 라이브러리에있는 자, 귀하의 경우, 당신은 단지 "두 장소에서 실행 파일을 넣지 못하도록"식별자를 정의 할 수 있습니다)

  • Windows의 경우 : 기존의 경우 파일을 제거하고 os.O_CREAT | os.O_EXCL | os.O_RDWR POSIX 호환 시스템의
  • 으로 파일을 작성하지 않은 경우 : 사용하여 파일을 만들고 여기에 대한 잠금을 획득 기존의 경우 파일을 제거 할 첫번째 시도와 그렇지 않은 경우 fcntl.LOCK_EX | fcntl.LOCK_NB

프로그램을 의미있는 실패는 이미

를 실행 한 다음이 말해 두 버전 재치 빌드 코멘트를 작성할 수 있도록 (POSIX 시스템) 잠금을 해제하기 위해 연기 액션을 사용하여 파일

이동을 삭제할 수 있습니다 컴파일 할 파일

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

내가 그것을 밖으로 라이브러리를 시작했습니다 테스트 : 당신이 유닉스 윈도우의 시스템

// +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 
} 

에 대한

가 귀하의 OS에 보내고 that you can find here

관련 문제