I don't have Tkx going, but in Tk, you could do it like this. In the thread, when you launch your program, don't use system, but use a form of IPC which will return a pid for the batch file running. Then stuff the pid in a threads shared variable,
then in your main Tkx script, the cancel button would invoke "killfam 9, $pid". Use Proc::Killfam to make sure you kill not only the batch file, but any shell which gets invoked to run it.
A simple example in Tk, to show the principle. Tkx should work similarly.
#!/usr/bin/perl
use warnings;
use strict;
use threads;
use threads::shared;
use Tk;
my %shash;
#share(%shash); #will work only for first level keys
my %hash;
share ($shash{'go'});
share ($shash{'fileno'});
share ($shash{'pid'});
share ($shash{'die'});
$shash{'go'} = 0;
$shash{'fileno'} = -1;
$shash{'pid'} = -1;
$shash{'die'} = 0;
$hash{'thread'} = threads->new(\&work);
my $mw = MainWindow->new(-background => 'gray50');
my $text = $mw->Scrolled('Text')->pack();
my $startb = $mw->Button( -text => 'Start',
-command=>sub{
$shash{'go'} = 1;
$mw->after(100); #give pipe chance to startup
my $fileno = $shash{'fileno'};
print "fileno_m $fileno\n";
open (my $fh, "<&=$fileno") or warn "$!\n";
# filevent works but may not work on win32,
# but you can use a timer instead as shown below
$mw->fileevent(\*$fh, 'readable', );
while(<$fh>){
$text->insert('end',$_);
$text->see('end');
$mw->update;
}
# on Win32 (untested by me) you will need
# a timer instead of fileevent
# my $repeater;
# $repeater = $mw->repeat(10,
# sub {
# my $bytes = sysread( "<&=$fileno", my $buf, 8192);
# $text->insert('end',$buf);
# $text->see('end');
# if( $shash{'go'} == 0 ){ $repeater->cancel }
# }
# );
}
)->pack();
my $stopb = $mw->Button( -text => 'Stop/Exit',
-command=>sub{
$shash{'die'} = 1;
kill 9,$shash{'pid'};
$hash{'thread'}->join;
exit;
},
)->pack();
MainLoop;
##################################################################
sub work{
$|++;
while(1){
if($shash{'die'} == 1){ return };
if ( $shash{'go'} == 1 ){
#run your command here, and try to find a way to capture it's
+output
# on win32 you may need to use IPC::Run in the thread
#use a win32 command that gives continous output
# on linux I use top
my $pid = open(FH, "top -b |" ) or warn "$!\n";
my $fileno = fileno(FH);
print "fileno_t->$fileno\n";
$shash{'fileno'} = $fileno;
$shash{'pid'} = $pid;
$shash{'go'} = 0; #turn off self before returning
}else
{ select(undef,undef,undef,.1) } #short sleep
}
}
#####################################################################
| [reply] [d/l] |
Hi, firstly thanks for your support regarding my thread issues. :) I was not able to try out the Proc::Background method cause our active state version does not have this package by default. (well i can download it i know, but as other people might try to run this code, i figured i'd stick to the common packages). Anyway, I looked at your thread though and tried the queuing and seems like it's the (thread-safe) way to go and is a much better design, but I still end up with the same problem. Though now i think I found something is wrong with my question, it should have read "Cancel the BATCH file executed by a system call from a thread in main." pardon my mistake. any thoughts?
| [reply] |
| [reply] |
my @jobs ;
...
push @jobs, Proc::Background->new( $command, $arg1, $arg2 );
...
$jobs[0]->die if $jobs[0]->alive;
| [reply] [d/l] |