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

Hi, people!

I just got a problem. I need to execute complex command lines in my program. Problem is that some system (...) calls can hang, so the script will also hang. So I determined to write multithreaded program and give some timeout for each system call.

So, there is some thread, and it made system("badprog.exe"); how can I stop the process from another thread?

P.S. Win32::Process is almost good for me, but it allows only simple program calls, not complex calls. The problem seems to be unresolvable... I need straight solution, not workarounds such as .bat-files.

Thank you!

Replies are listed 'Best First'.
Re: break thread with system(...) call
by BrowserUk (Patriarch) on Jul 16, 2008 at 19:13 UTC

    Without threads:

    ## Start the program asynchronously my $pid = system 1, "padprog.exe"; ## Wait for some period sleep $timeout; ## If program is still running, kill it kill 1, $pid if kill 0, $pid;

    Be aware that if your command contains shell meta characters, then the pid will be for cmd.exe, not whatever exectuable it starts, and killing the shell won't normally kill the other process


    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.
      great! it seems to be the most progressive... I see, you understand the problem as for complex scripts and so cmd.exe ... but I think that it will be some kind of process tree for windows, I'm right?
      perl->cmd.exe->prog.exe

      maybe there is a way to follow the process tree or kill cmd.exe in such a way that all children will be also killed? Thaanks)
        maybe there is a way to follow the process tree or kill cmd.exe in such a way that all children will be also killed?

        Yes. Use Win32::CreateProcess and the include CREATE_NEW_PROCESS_GROUP. Use it to start cmd.exe and then supply your complex command line.

        When you kill cmd.exe, any child processes it has created will be killed also.


        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: break thread with system(...) call
by zentara (Cardinal) on Jul 16, 2008 at 19:06 UTC
    Alarms don't work well with threads. What is generally done, is to start a separate timer thread, and use shared variables to communicate between the 2. Probably if your prog.exe hangs, you will need to kill it by it's pid (or whatever on windows). So start your prog.exe in a thread, get it's pid and put it in a shared variable. At the same time, start your timer in another thread ( or in a Tk::After in main). When it timeouts, read the pid from the shared variable and kill it, if it hasn't finished.

    I'm not really a human, but I play one on earth CandyGram for Mongo
      Sorry, such thing will not work.
      1) Win32::Process does what you say even more elegantly..
      2) Everything around threads and shared things I have implemented - such a wrapper
      3) So, this will not work because of I will have to use complex commands, such as system ("FOR /R %g DO prog.exe %g ")
      So, you see, common process launch will not work :(

      But nevertheless, Thanks for useful info about that alarms don't work well with threads!).. now I don't know what to do.

      If there will be no ideas, I'll use .bat-files or Win32::Process..
        Contrary to what you said, (3) will work with CreateProcess. Remember that it's a shell command, so launch cmd.exe to execute the command. system uses CreateProcess, so anything system can do, so can CreateProcess.
        A separate timer thread will work if you set it up right, I don't understand why it wouldn't. You start 2 threads, which run independent. When the timer reaches the end of it's code block, if a finished flag isn't set, it kills the pid from the other thread. But I don't use windows, and maybe I don't experience it's peculiarities. This works on linux. (Granted it is easier if you have an eventloop system in main).
        #!/usr/bin/perl -w use strict; use threads; use threads::shared; #my $finished:shared = 0; my $timer_go:shared = 0; #my $worker_go:shared = 0; #my $worker_pid:shared = ''; my $worker = threads->create(\&worker); my $timer = threads->create(\&timer,$worker); print "hit enter to start\n"; <>; $timer_go=1; <>; $timer->join(); $worker->join(); sub timer { my $worker = shift; while(1){ if($timer_go){ my $count = 0; while(1){ $count++; if($count > 5){ print "timed out\nHit enter to finish\n"; # Send a signal to a thread $worker->kill('INT'); return; } sleep 1; print "timing $count\n"; } }else{sleep 1} } } sub worker { $|++; $SIG{INT} = sub{ warn "Caught Zap!\n"; sleep 1; exit; }; my $worker_pid = open( READ, "top -d 1 -b |" ); print "\t$worker_pid\n"; return; }

        I'm not really a human, but I play one on earth CandyGram for Mongo
Re: break thread with system(...) call
by cdarke (Prior) on Jul 17, 2008 at 08:29 UTC
      Thanks! I've looked for description of it and seems it matches what I need, but I decided to use another solution (please look slighter above if interesting) - it doesn't need any installations from CPAN and seems to work well...
Re: break thread with system(...) call
by moritz (Cardinal) on Jul 16, 2008 at 18:42 UTC
    alarm sets timeouts, and at least on linux this also aborts external programs. I don't know if that works well on windows, though.
      oh, great! thanks! it works (even here, on windows XP), but launched process (I'm testing launching notepad.exe) is not closed... are there any ideas? It must be closed because after some time the server will be overflooded with the hanging processes.