Perl语言的多线程(二)

很多时候使用perl多线程可以达到很不错的效果,可以节约很多时间完成很复杂的工作。但通过perl threads模块的描述文件可以看到,它也有很多缺点。比如说在使用perl多线程的时候,必须的保证所有引用的模块都是支持thread。而在实际应用中,我们很难做到这样。比如我们要多线程,但同时要应用OLE模块去操作activex。 此用例应该是一种很常见的用例。那是不是意味着此时我们不得不放弃使用多线程呢。 非也, 本文介绍一种可以使用多线程和ole的例子。

 在http://www.cpan.org/官方网站上对这种情况给出的方案是:

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。

再次,主要讨论一下第二种情况,既主要是该非thread模块放到方法中引用。下面是一个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;
}

 

在此例子中,用到了queue,它的作用是将非thread 安全的数据通过管道传输,这样能避免他们互相调用。

posted @ 2009-11-27 21:33  Jonson Li  阅读(610)  评论(0编辑  收藏  举报