http://www.perlmonks.org?node_id=1055548

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

My code uses fork() and waitpid(-1,&WNOHANG) to spawn multiple children. Each of these children uses $pid = system(1,"start $executable $args") to start a program. This program sometimes hangs, and I would like to be able to kill it after some length of time. The $pid value returned by my system command is not the one I need to kill the process (From my research I believe this has to do with a shell?) and I'm stuck as to how to get around this. I've experimented with a piped open and had no luck, but I'm not sure if I'm doing it correctly. Any suggestions as to how I can get a PID so that I can kill the process later if needed? Sorry if this has already been answered, but I'm fairly new to coding and Perl, and I've looked at several similar questions and can't figure out how to apply them to get a workable solution. Also, my OS is Windows 7 64 bit and I can't use any modules that aren't standard. Thanks in advance for any advice!

Update: Thanks for all the replies! I found a not so elegant workaround that completely avoids the problem of getting the PID. For reasons other than the PID problem, I have to copy the executable to a new directory before I run it, and I now give the duplicate a unique name each time I copy it. Then, if it is still going after a certain amount of time, I kill it with start("Taskkill /IM $unique_executable /F"). A little bit clunky, but it works for my purposes.

Replies are listed 'Best First'.
Re: How do you get the PID of an external process?
by BrowserUk (Patriarch) on Sep 25, 2013 at 02:23 UTC
    Each of these children uses $pid = system(1,"start $executable $args") to start a program.

    Don't use start in your command. Start requires a shell to run your program and it is the pid of that shell that is returned to you.

    Just use: my $pid = system 1, "$executable $args";


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.

      Hi BrowserUK,

      I'm really curious if this kind of call is a speciality on Windows or something special in Perl on Windows. I don't know that API. Can you give me a pointer to the relevant documentation?

      Thank you in advance

      McA

        Beyond, How does system(1,"foo") work on Windows? & similar, I've never seen it documented. Damn glad it exists though :)


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re: How do you get the PID of an external process?
by syphilis (Archbishop) on Sep 24, 2013 at 23:37 UTC
    I can't use any modules that aren't standard

    There's a standard module called Win32, and you might be able to make use of its GetCurrentProcessId() function.
    Here's the documentation for that function:
    Win32::GetCurrentProcessId() Returns the process identifier of the current process. Until the process terminates, the process identifier uniquely identifies the process throughout the system. The current process identifier is normally also available via the predefined $$ variable. Under fork() emulation however $$ may contain a pseudo-process identifier that is only meaningful to the Perl kill(), wait() and waitpid() functions. The Win32::GetCurrentProcessId() function will always return the regular Windows process id, even when called from inside a pseudo-process.
    Cheers,
    Rob
Re: How do you get the PID of an external process?
by McA (Priest) on Sep 24, 2013 at 23:21 UTC

    Hi,

    you say, that the forked childs use $pid = system(1,"start $executable $args") to start "a program". That would mean that the program you call has the name 1. Is that true?

    And looking at the documentation of system shows that the returned value is NOT the pid. So, please show us a little example.

    Regards
    McA

      system(1, $cmd) is a special case. IIRC, a hack provided on the port of Perl for Windows to support IPC::Open3 there.

      It just launches the given command on the background.