Beefy Boxes and Bandwidth Generously Provided by pair Networks
Your skill will accomplish
what the force of many cannot
 
PerlMonks  

Get the process id, and output of a process, in a threaded environment

by rmahin (Beadle)
on Sep 05, 2013 at 20:18 UTC ( #1052620=perlquestion: print w/ replies, xml ) Need Help??
rmahin has asked for the wisdom of the Perl Monks concerning the following question:

Ok perl monks, here is my issue.

Have a script that runs on both windows and unix (sun, aix, linux) platforms. I am trying to do this without using any perl modules not included by default to maintain complete portability. Most machines running this do not have access to the internet, so while far from impossible to install them, its an extra step I'm trying to avoid if possible.

The script is multithreaded, and each thread uses a piped open call to get the outputof a system process. The process I call needs specific environment variables set, so up until now I have been using the format open (my $output, '-|', 'set FOO=BAR& process'); and similar for unix.

This has been working beautifully, but now I would like to be able to kill the process started up from this call programmatically. For this, I need the pid, which the open call so kindly returns. Unfortunately setting the environment variables before hand, causes the open to return the process ID of the shell, and not the actual process.

I need a way to either set the environment variables for the perl script, in a thread-safe fashion, so that I can simply call the process directly in the open, OR...something else?

According to the documentation for unix machines setting the environment variables using %ENV is pretty much a no go when each thread needs different environments, so if there is a way around this, please let me know and it's something I can investigate further.

Here is a simple little script a made to just test this out, minus the threads. Using notepad as the process I call, just because its easy on windows. In it you can see that if you remove the environment variable, and kill the PID printed, notepad closes perfectly fine.

use strict; use warnings; $|++; print "Main PID is " . $$ . "\n"; my $pid = open my $output, '-|', 'set FOO=BAR& notepad.exe' or die $!; print "The PID returned is $pid\n"; print "=========================\n"; while(<$output>){ print $_; } close $output;
Also had a second script, which i used instead of calling notepad so I could see what that actual PID was
$|++; print "My actual PID is " . $$ . "\n"; print "Waiting for you to try and kill me now!\n"; <>;

Thanks in advance for taking a look!

UPDATE: The script in question is a multi-threaded tcp server, that utilizes a thread pool. The server accepts connections, passes work off to a thread pool, and one of the threads in the thread pool is responsible for executing the system command specified, reworking it is not entirely out of the question, but any notion of creating a new thread per connection and joining threads that are finished is not a viable solution. Reasons for this, can be seen found in this thread

Comment on Get the process id, and output of a process, in a threaded environment
Select or Download Code
Re: Get the process id, and output of a process, in a threaded environment
by BrowserUk (Pope) on Sep 05, 2013 at 21:07 UTC
    but now I would like to be able to kill the process started up from this call programmatically. For this, I need the pid, which the open call so kindly returns. Unfortunately setting the environment variables before hand, causes the open to return the process ID of the shell, and not the actual process.

    This problem really has nothing to do with threads. The same problem will manifest itself in a single threaded process. Ie. If you use the shell to invoke the executable, you'll get the pid of the shell not the executable.

    The solution is actually quite simple. Don't use the shell.

    You are using the shell in order to set up the environment that the executable will inherit. But, if you set the environment of your process to that you want the executable to inherit and then spawn the executable directly -- bypassing the shell -- you achieve your goal.

    Ie:

    { local %ENV = %ENV; ## make your additions (deletions, changes) here; $ENV{FOO} = 'BAR'; my $pid = open my $pipe, '-|', '/path/to/the/executable', @args or + die ...; sleep $someTime; kill KILL, $pid; } ## the changes to %ENV are undone once you reach here

    That's untested pseudocode.


    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.
      The problem is that on non MSWin systems, external commands are invoked with main thread's ENV, not the local one (as documented in the linked page):
      $ perl -Mthreads -e 'async { local %ENV = %ENV; $ENV{CPU} = "/"; open +my $PIPE, "echo \$CPU |"; print <$PIPE>}->join; $ENV{CPU}="MSWin"; sy +stem "echo \$CPU"' x86_64 MSWin
      لսႽ ᥲᥒ⚪⟊Ⴙᘓᖇ Ꮅᘓᖇ⎱ Ⴙᥲ𝇋ƙᘓᖇ

      Yes, the problem is not caused by threads at all as you said. The only reason I mentioned that aspect, is because setting values for %ENV are not picked up on unix machines unless they are set in the main thread. On windows, your code will work as expected with threads, but unix systems will not pick up those environment changes.

      Was writing up an example of my own, but the monk above me beat me to it. Love the community :)

        Then -- with the caveat that I don't have a non-Windows system to hand to test this -- make the changes in main before you spawn the thread. Eg:

        { my $running : shared = 0; local %ENV = %ENV; $ENV{ FOO } = 'BAR'; async{ my $pid = open ...; $running = 1; ... kill ... }->detach; ## Wait until the kid is spawned before exiting the scope. sleep 1 until $running; } ## And repeat till done.

        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.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://1052620]
Approved by sparkyichi
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (8)
As of 2014-12-29 11:59 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?





    Results (187 votes), past polls