Version 16 of How to get tcl to run only one instance of a script/application?

Updated 2011-10-27 17:45:04 by dkf

CT - Hi, I would like to ask the gurus out there if there is a sensible way of getting tcl to run only one instance of a script or application that works on all the platforms that tcl does. Thanks.

AM I do not quite understand your question. Could you describe what you mean by "only one instance" ? Do you by any chance mean "one script that works everywhere"? Or are there any other aspects, like particular directories ....?

LES: I think I know what (s)he wants because I have been looking for that too. Run a script with no "exit" statement: you have one instance. Run it again: you have two instances. So, (s)he wants only one instance running at any one time. In other words, the second instance would detect the first instance (or vice versa) and let the first instance run alone, but first probably passing to the first instance whatever argument/parameter this second instance was given. You're obviously a Unix/Linux user...

AM Guilty as charged - but I also use Windows a lot. It is just that my applications usually exit from time to time :)

NEM - Try singleton application. There may be other pages on this wiki which cover the same topic.

CT - Yes I did mean what LES has described. Its due to accessing a MetaKit database which causes havoc when more than one script is updating it at the same time as MK doesnt have concurrency yet. I've had a look at the singleton application page, thanks NEM, the socket approach seems solid enough. I was considering doing a very similar thing using send which I will still look into as it may be a lighter wieght solution to the socket approach. I will post the solution to that page if I implement it and it works well enough. Thanks all :)


dcw - 2011-10-26 15:21:57

Seems simple for unix:

  set pslst [exec ps -ef | grep mysingle.tcl]
  set cntr 0
  foreach i $pslst {
    if { $i == "tclsh" } {
      incr cntr
    }
  }
  if { $cntr == 1 } {
    puts "One instance of the script is running"
  } else {
    puts "$cntr instances of the script are running"
  }

MHo 2011-10-26: On windows, you could, for example, register yourself as a dde server with a fixed name. The very first thing each newly started instance should do then is to look if a dde server with name is already running (with dde services). Another method is to start a socket server on a specific port and try to connect to that port upon start. Or you could create a lock file and look for it... There are myriads of other methods all of which are more or less tricky...


dkf - 2011-10-27 13:43:21

One method is to use a server socket:

set socketID 12345;  # Pick something
try {
    socket -server {apply {{ch args} {
        close $ch
        raise .
    }}} -myaddr localhost $socketID
} trap {POSIX EADDRINUSE} {} {
    close [socket localhost $socketID]
}

OK, you might want a slightly less dumb protocol (e.g., passing a filename across) but that's just a refinement.