码迷,mamicode.com
首页 > 编程语言 > 详细

perl多线程使用

时间:2015-03-19 23:49:29      阅读:210      评论:0      收藏:0      [点我收藏+]

标签:

原文来自:博客园(华夏35度)http://www.cnblogs.com/zhangchaoyang 作者:Orisun

<<=========================threads===========================>>

#!/usr/bin/perl
use?threads (‘yield‘,
????????????‘stack_size‘?=> 64*4096,
????????????‘exit‘?=> ‘threads_only‘,
????????????‘stringify‘);
?
sub?start_thread {
???my?@args?= @_;
???print(‘Thread started: ‘, join(‘ ‘, @args), "\n");
}
?
##创建线程的方法
# my $thr = threads->create(‘func_name‘, ...);
# my $thr = threads->create(sub { ... }, ...);
# my $thr = threads->create(\&func, ...);
# The "->new()" method is an alias for "->create()".
my?$thr?= threads->create(‘start_thread‘, ‘argument1‘, ‘argument2‘);???? #通过create创建线程。返回线程实例
$thr->join();??????????????? #等待线程结束
threads->create(sub?{ print("I am a thread\n"); })->join();?????????????????? #创建一个线程,没有返回值。那这个线程实例如何访问呢?
?
my?$thr2?= async { foreach?(@ARGS) { print"$_\n"; } };????????????????????????????? #通过async使用匿名子例程创建线程
$thr2->join();
if?(my?$err?= $thr2->error()) {
???warn("Thread error: $err\n");
}
?
# 在隐式的列表环境中调用thread
my?$thr3?= threads->create(sub?{ return?(qw/a b c/); });
# 在显式的列表环境中调用thread
my?$thr4?= threads->create({‘context‘?=> ‘list‘},
?????????????????????????sub?{ return?(qw/a b c/); });
# 由于创建线程时使用的子例程返回的是列表,所以这里的join函数返回的也是列表
my?@results?= $thr3->join();
print?"@results\n";
# 把线程从主线程中分离出来
# $thr->detach();??????? ##报错:Cannot detach a joined thread,因为$thr已经调用过join()
$thr4->detach();???? ##
$tid?= $thr4->tid();
print?"线程4ID:$tid\n";
?
# Get a thread‘s object
$thr6?= threads->self();
$thr7?= threads->object($tid);
?
# Get a thread‘s ID
$tid?= threads->tid();
$tid?= "$thr7";???? #根据线程实例获得线程ID
?
# 给其他线程一个运行的机会
threads->yield();
yield();
?
# 返回未分离的线程列表
my?@threads?= threads->list();
my?$thread_count?= threads->list();
?
my?@running?= threads->list(threads::running);
my?@joinable?= threads->list(threads::joinable);
?
# 判断两个线程是相同
if?($thr4?== $thr2) {
???print?"thread4 equals to thread2.\n";
}
?
# 管理线程栈大小
$stack_size?= threads->get_stack_size();
$old_size?= threads->set_stack_size(32*4096);
?
# Create a thread with a specific context and stack size
my?$thr5?= threads->create({ ‘context‘????=> ‘list‘,
???????????????????????????‘stack_size‘?=> 32*4096,
???????????????????????????‘exit‘???????=> ‘thread_only‘?},
?????????????????????????\&start_thread);
?
# Get thread‘s context
my?$wantarray?= $thr->wantarray();
print?$wantarray,"\n";
?
# Check thread‘s state
if?($thr5->is_running()) {
???sleep(1);
}
if?($thr5->is_joinable()) {
???$thr5->join();
}
?
# Send a signal to a thread
$thr5->kill(‘SIGUSR1‘);
?
# Exit a thread
threads->exit();????????????????????????????????????

?

<<=========================Thread========================>>

$thread = Thread->new(\&start_sub)

$thread = Thread->new(\&start_sub,@args)

start_sub指定线程要执行的子例程,args是传给子例程的参数。

lock ?VARIABLE

给变量加锁,直到锁超出范围。给变量加锁只影响到lock函数的调用--即一个线程lock var1后,另一个线程再调用lovk var1时线程就会阻塞,但lock ?VARIABLE并不影响正常的对变量的访问。

如果锁往的是一个容器(如哈希或数组),那么其中的每一个元素并没有全部被锁住。比如一个线程中调用lock ?@arr,在另一个线程中调用lock $arr[3]时并不会阻塞。

async ?BLOCK;

async函数创建并返回一个线程实例,该线程要执行的代码全在BLOCK中,这里BLOCK是个匿名子例程,所以其后一定加分号。

Thread->self

返回调用Thread->self函数的线程实例。

Thread->list

返回non-joined和non-detached线程实例。

cond_waitLOCKED_VARIALBLE

cond_signal ?LOCKED_VARIALBLE

cond_broadcast ?LOCKED_VARIALBLE

上面3个函数主要用于线程问同步,都以一个已加锁的变量作为输入参数。当一个线程调用cond_wait后阻塞自己;当一个线程发出cond_broadcast后所有阻塞的线程得救;当一个线程发出cond_signal后只有一个阻塞的线程得救,至于是哪一个由系统内部决定。当然只有LOCKED_VARIALBLE参数相同时才为一组,大家才可以在一起玩同步。

yield

把CPU控制权交给另外一个线程,至于是哪个线程依赖于当时的运行环境。

join

等待一个线程结束并返回该线程结束时的返回值。

detach

分离的线程不允许被join。

equal

判断两个线程是否相同。

tid

返回线程的tid。tid是递增的,main线程的tid为0。

done

判断线程是否已经结束。

下面这3个函数在5005threads中还可以用,但是在ithreads中已经不可用了。

lock(\&sub)    eval    flags

<<============================threads::shared============================>>

默认下数据都是线程私有的,新创建的线程获得已有变量的一份私有拷贝。threads::shared用于在线程之间共享数据结构,可共享的数据类型只有6种,标量数据、数组、散列、以及它们的引用。

声明共享变量:

my ($scalar, @array, %hash);? ? ? ? ? ? ?

share($scalar);? ? ? ? ? ? ?

share(@array);? ? ? ? ? ?

?share(%hash);

share函数返回共享的值,这通常是一个引用。

也可以在编译时标记变量为共享变量:

my ($var, %hash, @array) :shared;

my?($var, %hash, @array) :shared;
?????????????my?$bork;
?
?????????????# Storing scalars
?????????????$var?= 1;
?????????????$hash{‘foo‘} = ‘bar‘;
?????????????$array[0] = 1.5;
?
?????????????# Storing shared refs
?????????????$var?= \%hash;
?????????????$hash{‘ary‘} = \@array;
?????????????$array[1] = \$var;
?
?????????????# 不能把非共享变量的引赋给一个共享变量,下面这3句是错误的
?????????????#?? $var = \$bork;??????????????????? # ref of non-shared variable
?????????????#?? $hash{‘bork‘} = [];?????????????? # non-shared array ref
?????????????#?? push(@array, { ‘x‘ => 1 });?????? # non-shared hash ref

shared_clone REF

?my $obj = {‘foo‘ => [qw/foo bar baz/]};? ? ? ? ? ?

?bless($obj, ‘Foo‘);? ? ? ? ? ? ?

my?cpy=sharedclone(obj);?

# Object status (i.e., the class an object is blessed into) is also ?cloned.? ? ? ? ? ?

print(ref($cpy), "\n"); ? ? ? ? # Outputs ‘Foo‘

对于克隆空的数组或散列,下面用法是等价的:

var?=?&share([]);???#?Same?asvar = shared_clone([]);? ? ? ? ? ? ?

var?=?&share({});???#?Same?asvar = shared_clone({});

is_shared VARIABLE

判断变量是否为共享变量,如果是则返回变量的内部ID(类似于refaddr函数),如果不是返回undef。

如果is_shared参数是数组或散列,它并不检查容器中的元素是否为共享变量。如下

my?%hash?:shared;
?????????????if?(is_shared(%hash)) {
?????????????????print("\%hash is shared\n");
?????????????}
?
?????????????$hash{‘elem‘} = 1;
?????????????if?(is_shared($hash{‘elem‘})) {????????????????????????? ##返回undef
?????????????????print("\$hash{‘elem‘} is in a shared hash\n");
?????????????}

?lock VARIABLE

不能对容器内部的变量进行加锁:

?my %hash :shared;? ? ? ? ? ? ?

$hash{‘foo‘} = ‘bar‘;? ? ? ? ? ?

?#lock($hash{‘foo‘}); ? ? ? ? ?# Error? ? ? ? ? ?

?lock(%hash); ? ? ? ? ? ? ? ? ?# Works

cond_wait VARIABLE

cond_signal VARIABLE

cond_broadcast VARIABLE

这3个函数就不说了,跟threads里的一样。

cond_wait CONDVAR, LOCKVAR

当有其他线程signal第一个参数变量CONDVAR时,第二个参数变量LOCKVAR被解锁。

cond_timedwait VARIABLE, ABS_TIMEOUT? ? ? ?

cond_timedwait CONDVAR, ABS_TIMEOUT, LOCKVAR

如果signal未到达,而timeout了,同样会把变量解锁。

#? 创建一个共享的‘Foo‘ object
??????my?$foo?:shared = shared_clone({});
??????bless($foo, ‘Foo‘);
?
??????# 创建一个共享的 ‘Bar‘ object
??????my?$bar?:shared = shared_clone({});
??????bless($bar, ‘Bar‘);
?
??????# 把‘bar‘ 放到 ‘foo‘里面
??????$foo->{‘bar‘} = $bar;
?
??????# 通过线程重新bless the objects
??????threads->create(sub?{
??????????# Rebless the outer object
??????????bless($foo, ‘Yin‘);
?
??????????# 不能直接 rebless the inner object
??????????#bless($foo->{‘bar‘}, ‘Yang‘);
?
??????????# 重新取回然后 rebless the inner object
??????????my?$obj?= $foo->{‘bar‘};
??????????bless($obj, ‘Yang‘);
??????????$foo->{‘bar‘} = $obj;
?
??????})->join();
?
??????print(ref($foo),????????? "\n");??? # Prints ‘Yin‘
??????print(ref($foo->{‘bar‘}), "\n");??? # Prints ‘Yang‘
??????print(ref($bar),????????? "\n");??? # Also prints ‘Yang‘

注意:如果你还想使用threads,那么你必须在"use threads::shared"之前就"use threads",否则会报告异常。

如果你把一个数组、散列或它们的引用share以后,那么容器中的元素都会丢失。

my?@arr?= qw(foo bar baz);
????????share(@arr);
????????# @arr is now empty (i.e., == ());
?
????????# Create a ‘foo‘ object
????????my?$foo?= { ‘data‘?=> 99 };
????????bless($foo, ‘foo‘);
?
????????# Share the object
????????share($foo);??????? # Contents are now wiped out
????????print("ERROR: \$foo is empty\n")
????????????if?(! exists($foo->{‘data‘}));

所以正确的做法是你应该先把一个空的容器share,然后再往里面添加元素。

<<========================Thread::Semaphore=============================>>

use?Thread::Semaphore;
???????????my?$s?= Thread::Semaphore->new();
???????????$s->down();?? # P操作
???????????# The guarded section is here
???????????$s->up();???? # V操作
?
???????????# Decrement the semaphore only if it would immediately succeed.
???????????if?($s->down_nb()) {
???????????????# 邻界区在此
???????????????$s->up();
???????????}
?
???????????# 强制降低信号量即使他成为负数
???????????$s->down_force();
?
???????????# 创建信号量时指定·初始值
???????????my?$s?= Thread::Semaphore->new($initial_value);
???????????$s->down($down_value);
???????????$s->up($up_value);
???????????if?($s->down_nb($down_value)) {
???????????????...
???????????????$s->up($up_value);
???????????}
???????????$s->down_force($down_value);

<<===========================Thread::Queue===================================>>

直接看程序是学习语言的快速方法,注释得很清楚:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
use?strict;
???????????use?warnings;
?
???????????use?threads;
???????????use?Thread::Queue;
?
???????????my?$q?= Thread::Queue->new();????# 创建一个空的线程队列
?
???????????# Worker线程
???????????my?$thr?= threads->create(sub?{
???????????????????????????????????????while?(my?$item?=?$q->dequeue()) {
???????????????????????????????????????????#处理$item
???????????????????????????????????????}
????????????????????????????????????})->detach();
?
???????????# 向线程发送 work
???????????$q->enqueue($item1, ...);
?
?
???????????# 计算队列中有多少项
???????????my?$left?=?$q->pending();
?
???????????# 非阻塞地出队
???????????if?(defined(my?$item?=?$q->dequeue_nb())) {
???????????????# 处理 $item
???????????}
?
???????????# 获取队列中的第2项,注意并没有进行出几队操作
???????????my?$item?=?$q->peek(1);
?
???????????# 在队头后面插入两个元素
???????????$q->insert(1,?$item1,?$item2);
?
???????????# 提取队列中的最后两个元素
???????????my?($item1,?$item2) =?$q->extract(-2, 2);

上面代码中出现过的函数我就不介绍了。

下面的数据类型可以放入队列:
普通标题数据;

标量引用;

数组引用;

哈希引用;

以上对象的组合。

my @ary = qw/foo bar baz/;? ? ? ? ?

?q->enqueue(\@ary);?    ##copy?the?elements?‘foo‘,?‘bar‘?and?‘baz‘?from?@ary?intoq。

而对于共享变量,是它的引用进入队列,而没有发生元素的深复制。

my?@ary?:shared = qw/foo bar baz/;
???????????$q->enqueue(\@ary);
?
???????????my?$obj?= &shared({});
???????????$$obj{‘foo‘} = ‘bar‘;
???????????$$obj{‘qux‘} = 99;
???????????bless($obj, ‘My::Class‘);
???????????$q->enqueue($obj);

->new()    ##创建新队列

->new(LIST)  ##创建队列时压入元素

->enqueue(LIST)    #入队

->dequeue()    #从队中取出一个元素

->dequeue(COUNT)    #从队中取出COUNT个元素,如果COUNT大于队列长度,则阻塞,下面的方法不会阻塞。

->dequeue_nb()? ? ? ?

->dequeue_nb(COUNT)

->pending()

返回队列中元素的个数。

{
??????lock($q);?? # 销往队列,以防止其他线程中修改和删除队列元素
??????my?$item?= $q->peek();
??????if?($item?...) {
??????????...
??????}
??}
??# 离开块之后,队列变量自动解锁

->peek()      #取出队首元素,并没有出险

->peek(INDEX)    #取出指定下标的队列元素,INDEX为负数时是从队尾开始数起

->insert(INDEX,LIST)    #在指定的位置上插入一组元素,队首元素的INDEX为0

->extract()

->extract(INDEX)? ? ? ?

->extract(INDEX, COUNT)

删除并返回指定的元素。

原文来自:博客园(华夏35度)http://www.cnblogs.com/zhangchaoyang 作者:Orisun

perl多线程使用

标签:

原文地址:http://www.cnblogs.com/lyon2014/p/4351934.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!