Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

Windows process

by qadwjoh (Scribe)
on Sep 16, 2004 at 13:38 UTC ( [id://391438]=perlquestion: print w/replies, xml ) Need Help??

qadwjoh has asked for the wisdom of the Perl Monks concerning the following question:

Hi

I'm currently writing a script of which only one instance may run at any time, on Windows. I'd like to achieve this by checking all current running processes for instances of the script which are still active, just after the script is launched, then quitting if any are found.

The problem in the code example that I've tried (which uses Win32::PerfLib), perl processes are simply labelled "Perl" and don't include any script name or parameter information so it's impossible to identify what script each instance of Perl is running.

Does anyone know how to do this?

thanks
A

Replies are listed 'Best First'.
Re: Windows process
by bpphillips (Friar) on Sep 16, 2004 at 13:52 UTC
    Usually you would handle this type of "single instance" issue with some sort of file locking mechanism. In doing a quick search on CPAN you might consider using Win32::Mutex or File::Flock.

    I haven't used either of those as the company I work with has our own in-house module to handle mutex situations.

    Here's a quick example (untested):
    use File::Flock; # the following croaks if it fails my $lock = new File::Flock("C:\lock_file"); # do whatever here # this will happen automatically once $lock # goes out of scope but it doesn't hurt to do # it explicitly once you're done with the lock $lock->unlock();
Re: Windows process
by bsdz (Friar) on Sep 16, 2004 at 15:09 UTC
    This will return a list of running process ids, names and their command lines on Windows XP and above. For Windows 2000 and lower you will need to find a workaround.
    use Win32::OLE; my $wmi = Win32::OLE->GetObject("winmgmts:") or die "wmi connect failed!"; my $P = $wmi->ExecQuery("SELECT * FROM Win32_Process") or die "Win32_Process connect failed!"; foreach my $p (in $P) { print join(',' , $p->ProcessId, $p->Name, $p->CommandLine)."\n"; }
    For more info on WMI and Win32_Process see Microsoft's documentaion
      This has been wrapped via Win32::Process::Info. And, it should work on 2000 and NT as well (SP4 or later for NT).

      In addition to the other suggestions, there's always the ol' pid file trick. It has also been wrapped - see Proc::PID::File.

      Dan

Re: Windows process
by traveler (Parson) on Sep 16, 2004 at 15:02 UTC
    Win32::Mutex sounds like a simple and appropriate solution. If you end up using File::Flock, beware of the case where a file exists after an abnormal termination of a process. That is, where there is a file and no process.

    Yet another approach is to use Tie::Registry to store the process id of the process in the Registry when it starts. The pseudo code would be something like this:

    if the key is in the registry and that process (value of the key) is still running, exit put the processid of the current process in the registry, creating the key if necessary "rest of program"
    HTH, --traveler
      Re: flock. But if the process dies, surely the lock is released from the file, so it doesn't matter if the lock file is left behind
Re: Windows process
by Tii (Monk) on Sep 16, 2004 at 13:58 UTC
    File locking definitely sounds like the way to go. When you're starting the new process, it can check if a particular file has been locked. If it has, the process knows that there is already a process running. If it hasn't, this process can lock it to indicate to any subsequent processes that there is already a process running. Should be pretty simple. HTH.
    Tii

      Merlyn has a neat trick whereby he places a lock on the script itself in a begin block. If the lock already exists at startup, the script is already being run. I forget the details, but a super search should find it.


      Examine what is said, not who speaks.
      "Efficiency is intelligent laziness." -David Dunham
      "Think for yourself!" - Abigail
      "Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon
        You mean this?

        # This is a trick used to prevent concurrent applications # from running, but that will work WITHOUT needing pid # or lock files, and so is kill -9 or power failure safe. # To work it needs a __DATA__ section to be defined at # the end of the file. use Fcntl 'LOCK_EX', 'LOCK_NB'; unless ( flock DATA, LOCK_EX | LOCK_NB ) { # An existing instance of this application is already running print STDERR "Program is already running\n"; exit(0); } __DATA__ Used as a lock to prevent concurrent execution. Do not remove this data section.


        Of course, I'm not sure how well it would work on Win32, but I'm sure there's an equivalent
Re: Windows process
by vladdrak (Monk) on Sep 17, 2004 at 00:20 UTC
    You can use the tlist.exe executable from the Resource Kit to get the 'CmdLine' for a running process. You need to pass tlist the pid as an arg and then parse the output, as you'll also get all the loaded modules and memory info. Another option would be to write the PID of the process out to a file and then check the file. As bsdz mentioned, you can also get the CmdLine param from WMI, on XP/2003. Tlist will work on NT4+.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://391438]
Approved by Grygonos
Front-paged by bart
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others examining the Monastery: (6)
As of 2024-03-28 21:23 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found