In many cases the use of multi-threaded perl can achieve very good results, it can save a lot of time to complete a very complex task. But you can see by the description file perl threads module, it also has many disadvantages. For example, when using multi-threaded perl, we must ensure that all modules are referenced support thread. In practical applications, it is difficult to do so. For example, we want to multi-threading, but at the same time to apply OLE module to operate activex. This use case should be a very common use case. Does that mean this time we had to abandon the use of multi-threading it. No, this article describes the example of a multi-threaded and can use the ole.
In http://www.cpan.org/ on the official website of this program, given that:
If the module will only be used inside a thread, you can try loading the module from inside the thread entry point function using require
(and import
if needed):
sub thr_func { require Unsafe::Module # Unsafe::Module->import(...); .... }
If the module is needed inside the main thread, try modifying your application so that the module is loaded (again using require
and ->import()
) after any threads are started, and in such a way that no other threads are started afterwards。
Once again, mainly to discuss the second case, both the main thread module into non-reference methods. Here is a demo.
use threads;
use threads::shared;
use Thread::Queue;
no warnings 'threads';
# Time out const
my $TIMEOUT : shared;
$TIMEOUT = 1;
# the sig for end thread
my $TERM : shared;
$TERM = 0;
#my $excel;
$SIG{'INT'} = $SIG{'TERM'} = sub{ print("\n>>> Terminating <<<\n"); $TERM=1;};
$SIG{'KILL'} = sub{ printf("%3d <- Killed\n", threads->tid());
threads->detach() if !threads->is_detached();
threads->exit(); };
sub ThreadWatcher
{
my $queue = shift;
my %timers;
while(!$TERM)
{
#print "ThreadWatcher -- TERM : $TERM\n";
while(my $tid = $queue->dequeue_nb())
{
if (! defined($timers{$tid}{'timeout'} = $queue->dequeue()) ||
! defined($timers{$tid}{'thread'} = threads->object($tid)))
{
# No timeout - unregister thread
delete($timers{$tid});
}
}
foreach my $tid (keys(%timers))
{
#print "$timers{$tid}{'thread'} \n";
if(--$timers{$tid}{'timeout'} < 0)
{
print "thread $timers{$tid}{'thread'} will be killed.\n";
$timers{$tid}{'thread'}->kill('KILL');
delete($timers{$tid});
}
}
# tick tock
sleep(1);
}
}
sub Worker
{
#eval {use Win32::OLE::Variant;};
my ($queue, $dataqueue) = @_;
# get the thread id and register with watch
my $tid = threads->tid();
printf("Working -> %3d\n", $tid);
$queue->enqueue($tid, $TIMEOUT);
print "Worker -- TERM : $TERM\n";
while(!$TERM)
{
#my $App = $dataqueue->dequeue();
my $data = $dataqueue->dequeue();
#deal with the data
#print "Worker -- DATA : $App\n";
print "Worker -- DATA : $data\n";
#my $var = Win32::OLE::Variant->new(VT_BSTR, $data);
#print "Worker VAR: $var\n";
}
# Remove signal handler
$SIG{'KILL'} = sub {};
# Unregister with timer thread
$queue->enqueue($tid, undef);
# Tell user we're done
printf("%3d <- Finished\n", $tid);
threads->detach() if ! threads->is_detached();
threads->exit();
}
# create time thread
my $watchQueue = Thread::Queue->new();
threads->create('ThreadWatcher', $watchQueue)->detach();
# create work thread
my $dataQueue = Thread::Queue->new();
threads->create('Worker', $watchQueue, $dataQueue);
NoneSafeModelScript('C:\Joe_Chen\Perl_Projects\Threads\update.xlsx');
WairLongTime(10);
sub WairLongTime
{
my $temp = $_[0];
$temp = $temp * 10000000;
for(my $index = 0; $index < $temp; $index++)
{
$index * $index;
}
return $index;
}
sub NoneSafeModelScript
{
eval 'use Win32::OLE';
eval 'use Win32::OLE::Variant';
my $excel;
for(my $index = 0; $index < 600; $index++)
{
print "Getting the Excel ActiveObject. Try # $index \n";
WairLongTime(1);
eval
{
$excel = Win32::OLE->GetActiveObject('Excel.Application') || Win32::OLE->new('Excel.Application', 'Quit');
};
if($@ or $excel == undef)
{
print "Unsuccessful: $@ \n";
if($index == 599)
{
print "ERROR:Don\'t got the Excel Application";
}
}
else
{
last;
}
}
my $path = $_[0];
my $book = $excel->workbooks->open($path);
my $sheet = $book->worksheets(1);
my $values = $sheet->Range("A1:D5")->{Value};
my $row_counts = $sheet->Range("A1:C3")->{Rows}->{Count};
my $column_counts = $sheet->Range("A1:C3")->{Columns}->{Count};
print "NoneSafeModelScript : $row_counts \n";
print "NoneSafeModelScript : $column_counts \n";
for(my $row=1; $row<$row_counts + 1; $row++)
{
my $array_ref = $sheet->Cells($row,1)->{Value};
print "NoneSafeModelScript : $array_ref \n";
my $var = Variant(Win32::OLE::Variant->VT_BSTR, $array_ref);
my $v = ref($var);
#my $v = $var->Type();
print "NoneSafeModelScript VAR: $var\n";
print "NoneSafeModelScript VAR: $v\n";
#$dataQueue->enqueue($var);
$dataQueue->enqueue($array_ref);
WairLongTime(2);
}
my $v = Variant(VT_DATE, "April 1 99");
print $v->Type, "\n";
print $v->Date(DATE_LONGDATE), "\n";
print $v->Date("ddd',' MMM dd yy"), "\n";
print Win32::OLE::Variant->VT_BSTR , "\n";
$book->Close;
$excel->Quit;
}
sub Wrap
{
my $value = $_[0];
my $var = Variant(VT_DATE, 'Jan 1,1970');
print "Wrap : $var \n";
return $var;
}
In this example, use the queue, it is the role of non-thread safe data transmission through the pipeline, so to avoid them call each other.
Reproduced in: https: //www.cnblogs.com/licheng/archive/2009/11/27/1612325.html