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

Hello,

First I want to say thank you for this thread http://www.perlmonks.org/?node_id=470827. I tried the example of BrowserUk.

It is working with Linux and Windows. Then I added a cancel button which kills the external process. It is working in windows, but in my ubuntu linux the process is NOT killed. Why?

Here the code:

#!perl -slw use strict; use threads; use threads::shared; use Thread::Queue; ## A shared var to communicate progess between work thread and TK my $Q = new Thread::Queue; my $pid:shared; sub work{ $pid = open PROC, 'perl -le"$|=1; print and select(undef,undef,undef,0.1) for 1 .. 1 +000" |' or die $!; while( <PROC> ) { $Q->enqueue( $_ ); } close PROC; } threads->new( \&work )->detach; use Tk; use Tk::ProgressBar; my $mw = MainWindow->new; my $pb = $mw->ProgressBar()->pack(); my $repeat; $repeat = $mw->repeat( 100 => sub { while( $Q->pending ) { my $progress = $Q->dequeue; return unless $progress; $repeat->cancel if $progress == 100; $pb->value( $progress ) } } ); $mw->Button('-text' => 'Cancel', '-command' => sub{ kill 9, $pid })->pack(); $mw->MainLoop;

My question: Why is the killing of the external process with kill working in Windows and NOT working in Linux?

Thank you

Greetings,

Dirk

Replies are listed 'Best First'.
Re: Tk and IPC - killing of process not working in Linux
by chrestomanci (Priest) on Feb 12, 2011 at 22:15 UTC

    I downloaded your script and ran it under the perl debugger on my linux box. As described the Cancel button did not kill the process.

    I set a breakpoint on sub work(), and made a note of $pid, and the pid of the perl process.

    DB<1> b work DB<2> c main::work(test.pl:12): $pid = open PROC, main::work(test.pl:13): 'perl -le"$|=1; print and select(undef,und +ef,undef,0.1) for 1 .. 1000" |' main::work(test.pl:14): or die $!; DB<2> n DB<2> x $pid 0 9940 DB<3> x $$ 0 9850

    From there, I ran pstree in a normal bash shell to check the child processes of the perl script:

    /tmp$ pstree -apA 9850 perl,9850 -d -I /etc/perl -I /usr/local/lib/perl/5.10.1 -I /usr/local/ +share/perl/5.10.1 -I |-sh,9940 -c perl -le"$|=1; print and select(undef,undef,undef,0.1) +for 1 .. 1000" | `-perl,9941 -le$|=1; print and select(undef,undef,undef,0.1) for + 1 .. 1000 `-{perl},9939

    What this basically means, is that when you stated the test process, you actually started a shell which started the test process. It was the process ID of that shell that you had stored in $pid. When you sent a kill signal to that PID your killed the shell, but not it's child process.

    I think you need to figure out how to start your process without going via a shell. I know you can do it via a fork/exec but that is probably to heavyweight and not portable to windows. There are probably other ways, but I don't know them off the top of my head. I suggest you read perlipc.

      Thank you very much. The hint with the shell helps me a lot.

      Here a solution which is working for Linux and Windows:

      #!perl -slw use strict; use threads; use threads::shared; use Thread::Queue; ## A shared var to communicate progess between work thread and TK my $Q = new Thread::Queue; my $pid:shared; sub work{ if( $^O eq "linux" ) { $pid = open PROC, "-|", "perl", "-le", '$|=1; print and select(undef,undef,undef,0.1) for 1 .. 1000' or die $!; } elsif( $^O eq "MSWin32" ) { $pid = open PROC, 'perl -le"$|=1; print and select(undef,undef,undef,0.1) for 1 .. 1 +000" |' or die $!; } else { die "Not implemented for $^O"; } if( $pid ) { while( <PROC> ) { $Q->enqueue( $_ ); } close PROC; } } threads->new( \&work )->detach; ## For lowest memory consumption require (not use) ## Tk::* after you've started the work thread. use Tk; use Tk::ProgressBar; my $mw = MainWindow->new; my $pb = $mw->ProgressBar()->pack(); my $repeat; $repeat = $mw->repeat( 100 => sub { while( $Q->pending ) { my $progress = $Q->dequeue; return unless $progress; $repeat->cancel if $progress == 100; $pb->value( $progress ) } } ); $mw->Button('-text' => 'Cancel', '-command' => sub{ kill 9, $pid })->pack(); $mw->MainLoop;

      In perlipc I read that if you give an open to minus more than 3 arguments, than the shell is not called.

      This solution is ok for me. But of course I'd prefer how to find out the pid of the process I want to kill. Independent whether it is called by a shell or not.

      And the other interesting question is why linux is using a shell and windows not?

      Greetings,

      Dirk

Re: Tk and IPC - killing of process not working in Linux
by BrowserUk (Patriarch) on Feb 12, 2011 at 20:55 UTC

    Are you sure that the secondary process is actually starting? Because the command you've posted uses Windows quoting not *nix shell quoting:

    perl -le"$|=1; print and select(undef,undef,undef,0.1) for 1 .. 1000" ........^..........................................................^

    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.

      Yes, the secondary process is starting because I can see that the progressbar is filling slowly.

      What would be the right quoting for Linux? Single quotes?

        Yes, the secondary process is starting because I can see that the progressbar is filling slowly.

        Very strange.

        What would be the right quoting for Linux? Single quotes?

        Yes.

        I've now exhausted my limited knowledge of *nix. You'll need someone that uses it to solve your problem.


        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: Tk and IPC - killing of process not working in Linux
by Khen1950fx (Canon) on Feb 13, 2011 at 05:31 UTC
    I used  sub {$mw->destroy})->pack();

    #!perl -slw use strict; use threads; use threads::shared; use Thread::Queue; ## A shared var to communicate progess between work thread and TK my $Q = new Thread::Queue; my $pid:shared; sub work{ $pid = open PROC, 'perl -le"$|=1; print and select(undef,undef,undef,0.1) for 1 .. 1 +000" |' or die $!; while( <PROC> ) { $Q->enqueue( $_ ); } close PROC; } threads->new( \&work )->detach; use Tk; use Tk::ProgressBar; my $mw = MainWindow->new; my $pb = $mw->ProgressBar()->pack(); my $repeat; $repeat = $mw->repeat( 100 => sub { while( $Q->pending ) { my $progress = $Q->dequeue; return unless $progress; $repeat->cancel if $progress == 100; $pb->value( $progress ) } } ); $mw->Button( '-text' => 'Cancel', '-command' => sub {$mw->destroy})->pack(); $mw->MainLoop;
Re: Tk and IPC - killing of process not working in Linux
by ww (Archbishop) on Feb 12, 2011 at 20:50 UTC
    Update: Got OP's problem backwards. My reply is irrelevant but I'm leaving it lest some future reader actually be seeking info re 'doze kill.

    Which "Windows?"

    I believe you'll find that kill -- probably an alias for the commandlet Stop-Process -- is -- generally -- NOT native to older w32 OSen and, when extant, a functional counterpart may have another name.

    I also believe you may find a Posix kill in a Cygwin install, but the really short answer is "You'll have to research the documentation for the 'Windows' in question."