how to restrict the program run only one instance

3,919 views
Skip to first unread message

Shark Flh

unread,
Jan 21, 2014, 10:52:34 PM1/21/14
to golan...@googlegroups.com
how to restrict the program run only  one instance
what method can work on windows and Linux both system?

for example I have a program test.exe, I copy it to 2 dir
a/test.exe
b/test.exe
I want  restrict the test.exe can only run one instance from each dir.

i tried open  file use ModeExclusive,but it doesn't on windows.

Dave Cheney

unread,
Jan 21, 2014, 11:29:09 PM1/21/14
to Shark Flh, golang-nuts
Listen on a port on localhost, this will block anybody else from binding to the same port until the first program exits.,


--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

DV

unread,
Jan 21, 2014, 11:33:14 PM1/21/14
to golan...@googlegroups.com
Not sure what the correct, cross-platform way to do this is, but at least on Windows, the recommended approach (and the one that has worked great for me) is to use the CreateSemaphore function. If the name you specify starts with "Global\", then the semaphore is unique for the entire system and a second attempt to open it will fail. 


Getting this to work through cog shouldn't be too bad

Shark Flh

unread,
Jan 22, 2014, 12:10:42 AM1/22/14
to golan...@googlegroups.com, Shark Flh
for example I have a program test.exe, I copy it to 2 dir
a/test.exe
b/test.exe

then a/test.exe and b/test.exe only one can run.
I need both of it can run one instance.

BTW, when program exit by accident , sometime the port will be locked, then  it can't restart.

Shark Flh

unread,
Jan 22, 2014, 12:13:41 AM1/22/14
to golan...@googlegroups.com
thanks, but I really need a cross-platform solution.

Dave Cheney

unread,
Jan 22, 2014, 12:21:12 AM1/22/14
to Shark Flh, golang-nuts
On Wed, Jan 22, 2014 at 4:10 PM, Shark Flh <flhs...@gmail.com> wrote:
for example I have a program test.exe, I copy it to 2 dir
a/test.exe
b/test.exe

then a/test.exe and b/test.exe only one can run.
I need both of it can run one instance.

BTW, when program exit by accident , sometime the port will be locked, then  it can't restart.

This is not true. When a program exits, any sockets owned by that process will be closed as well.

Hai Thanh Nguyen

unread,
Jan 22, 2014, 3:39:08 AM1/22/14
to golan...@googlegroups.com
Just write something to a file somewhere. Everytime your program is run, check that file. You don't need any fancy functionalities to do this.

Konstantin Khomoutov

unread,
Jan 22, 2014, 5:15:04 AM1/22/14
to Hai Thanh Nguyen, golan...@googlegroups.com
On Wed, 22 Jan 2014 00:39:08 -0800 (PST)
Hai Thanh Nguyen <phai...@gmail.com> wrote:

> Just write something to a file somewhere. Everytime your program is
> run, check that file. You don't need any fancy functionalities to do
> this.

This fails if a program gets killed and has no chance to perform
cleanup, so the file becomes stale. This moves us to the "PID file"
concept famous in classic Unix daemons -- a new instance of the daemon
is supposed to check if the PID file exists, and when it does whether
the process with this PID file exists, and if it does whether its
binary path name is that of the daemon. This is complicated and is
inherently racey.

So listening on a socket (not necessarily TCP -- Unix-domain socket
would do as well; on Linux it's possible to create an UD-socket which
does not physically exists on a file system) or connecting to d-bus and
requesting a well-known name would do as well in a non-racey fashion.

Robert Johnstone

unread,
Jan 22, 2014, 9:04:19 AM1/22/14
to golan...@googlegroups.com
It may be easier to use the standard method on each platform, and then wrap that behaviour into a package.  DV has gotten you halfway there.  Now you just need a solution on linux... (depending on what platforms you are targeting).

oneinstance_windows.go
oneinstance_linux.go
etc.

polla...@gmail.com

unread,
Jan 22, 2014, 11:45:44 PM1/22/14
to golan...@googlegroups.com, Hai Thanh Nguyen


On Wednesday, January 22, 2014 5:15:04 AM UTC-5, Konstantin Khomoutov wrote:
On Wed, 22 Jan 2014 00:39:08 -0800 (PST)
Hai Thanh Nguyen <phai...@gmail.com> wrote:

> Just write something to a file somewhere. Everytime your program is
> run, check that file. You don't need any fancy functionalities to do
> this.

[...] This moves us to the "PID file"
concept famous in classic Unix daemons -- a new instance of the daemon
is supposed to check if the PID file exists, and when it does whether
the process with this PID file exists, and if it does whether its
binary path name is that of the daemon.  This is complicated and is
inherently racey.

PID files are not really that complicated.  You can avoid race conditions by requiring any new process that wants to take over to acquire a lock while they're testing whether the process recorded in the lock file is still active or not; when they release the lock, they'll either have exited or overwritten the PID file with their own pid.

So listening on a socket (not necessarily TCP -- Unix-domain socket
would do as well; on Linux it's possible to create an UD-socket which
does not physically exists on a file system) or connecting to d-bus and
requesting a well-known name would do as well in a non-racey fashion.

Listening on a socket is a good if you only want a single copy of the program running per machine, and you want it to be running all the time.  (Otherwise, you would need to worry about losing your socket to some pther process.)  If you wanted to have one copy of the process per user, or one per some other entity, then the PID file mechanism is a little more natural.

Tom

Andrew Walker

unread,
Sep 19, 2015, 10:52:21 AM9/19/15
to golang-nuts
I took a stab at solving this for windows using the CreateSemaphore call, but have found it frustratingly elusive.  From reading the documentation, creating a semaphore with the prefix "Global\", and then attempting to re-create it in another process will still return the handle, but GetLastError() should return ERROR_ALREADY_EXISTS.  My code, however, always succeeds. GetLastError() always returns 0, and syscall.GetLastError() is always nil. Anyone see anything obvious that I'm missing?

//oneinstance_windows.go
package oneinstance

import (
"fmt"
"syscall"
"unsafe"
)

var (
modkernel32      = syscall.NewLazyDLL("kernel32.dll")
pCreateSemaphore = modkernel32.NewProc("CreateSemaphoreA")
pGetLastError = modkernel32.NewProc("GetLastError")
)

func GetLastError() uint32 {
ret, _, _ := pGetLastError.Call()
return uint32(ret)
}

func GetInstance(ident string) error {
semaphoreName := uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(`Global\` + ident)))
//ret, _, _ := pCreateSemaphore.Call(
pCreateSemaphore.Call(
0,
uintptr(1),
uintptr(1),
semaphoreName,
)

fmt.Println(GetLastError())
fmt.Println(syscall.GetLastError())
if GetLastError() != 0 {
return syscall.GetLastError()
}
return nil
}


package main

import (
"fmt"
"os"
"time"

)

func main() {
err := oneinstance.GetInstance("foo")
if err != nil {
fmt.Println("Can't get semaphore:", err)
os.Exit(1)
}

fmt.Println("Got semaphore")
time.Sleep(10 * time.Second)
}

If I open two separate terminal windows and run the resultant exe, both of them will say "got semaphore" and pause.

Andrew Walker

unread,
Sep 19, 2015, 11:02:51 AM9/19/15
to golang-nuts
Incidentally, I get similar results when using CreateMutex

    pCreateMutex.Call(
        0,
        1,
        semaphoreName,
    )

brainman

unread,
Sep 19, 2015, 10:01:02 PM9/19/15
to golang-nuts
On Sunday, 20 September 2015 00:52:21 UTC+10, Andrew Walker wrote:
> ... GetLastError() always returns 0,

I am not surprised that GetLastError returns something inconsistent. GetLastError is returning error for the "last WinAPI call on current thread". How do you know Go runtime is not making WinAPI calls at random moments in your program? You should use pCreateSemaphore.Call return parameters instead. 3rd parameter will have GetLastError value in it at the time of CreateSemaphore call. You should, obviously, check CreateSemaphore return value (pCreateSemaphore.Call return value number 1) first, to decide if it succeeded or failed.

Alex

Andrew Walker

unread,
Sep 19, 2015, 10:52:31 PM9/19/15
to golang-nuts
Ugh, you're absolutely right. Error resolved. Package pending.

ankurgu...@gmail.com

unread,
Jun 4, 2016, 10:30:14 AM6/4/16
to golang-nuts
The simplest solution would be to do it using MUTEX, here is how to do it along with description.

Rodolfo Amaral

unread,
Sep 17, 2016, 3:50:05 PM9/17/16
to golang-nuts, ankurgu...@gmail.com
I know this topic is a bit old, but I needed it recently on Windows and I'll post here how I did it in case someone else needs.

I used Windows mutex as described by ankurgu..@gmail.com:

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

I created a lib with a more complete example: https://github.com/rodolfoag/gow32

Thx!
Reply all
Reply to author
Forward
0 new messages