深入剖析Perl线程的生命周期

开发 架构
本文向大家介绍一下Perl线程的生命周期概念,和现有大多数Perl线程模型不同,在PerlithreadsPerl线程模型中,默认情况下任何数据结构都不是共享的。

本文和大家继续讨论一下Perl线程的生命周期,主要包括共享与同步,锁,信号量和Perl线程队列几部分内容,相信通过本文的学习你对Perl线程生命周期的概念有一定的了解。

共享与同步

threads::shared

和现有大多数Perl线程模型不同,在PerlithreadsPerl线程模型中,默认情况下任何数据结构都不是共享的。当一个新Perl线程被创建以后,它就已经包含了当前所有数据结构的一份私有拷贝,新建Perl线程中对这份拷贝的数据结构的任何操作都不会在其他Perl线程中有效。因此,如果需要使用任何共享的数据,都必须显式地申明。threads::shared包可以用来实现Perl线程间共享数据的目的。

多Perl线程间既然有了共享的数据,那么就必须对共享数据进行小心地访问,否则,冲突在所难免。PerlithreadsPerl线程模型中内置的lock方法实现了Perl线程间共享数据的锁机制。有趣的是,并不存在一个unlock方法用来显式地解锁,锁的生命周期以代码块为单位,也就是说,当lock操作所在的代码块执行结束之后,也就是锁被隐式释放之时。例如


清单10.Perl线程中的锁机制    
 

  1. usethreads::shared;  
  2.  
  3. #inthread1  
  4. {  
  5. lock($share);#lockfor3seconds  
  6. sleep(3);#otherthreadscannotlockagain  
  7. }  
  8. #unlockimplicitlynowaftertheblock  
  9.  
  10. #inthread2  
  11. {  
  12. lock($share);#willbeblocked,asalreadylockedbythread1  
  13. $share++;#afterthread1quitfromtheblock  
  14. }  
  15. #unlockimplicitlynowaftertheblock  
  16.  

 上面的示例中,我们在thread1中使用lock方法锁住了一个普通的标量,这会导致thread2在试图获取$share变量的锁时被阻塞,当thread1从调用lock的代码块中退出时,锁被隐式地释放,从而thread2阻塞结束,lock成功以后,thread2才可以执行$share++的操作。对于数组和哈希表来说,lock必须用在整个数据结构上,而不是用在数组或哈希表的某一个元素上。

假如一个Perl线程对某一个共享变量实施了锁操作,在它没有释放锁之前,如果另外一个Perl线程也对这个共享变量实施锁操作,那么这个Perl线程就会被阻塞,阻塞不会被自动中止而是直到前一个Perl线程将锁释放为止。这样的模式就带来了我们常见的死锁问题。

例如
清单12.Perl线程中的死锁    
 

  1. usethreads;  
  2. usethreads::shared;  
  3. #inthread1  
  4. {  
  5. lock($a);#lockfor3seconds  
  6. sleep(3);#otherthreadscannotlockagain  
  7. lock($b);#deadlockhere  
  8. }  
  9.  
  10. #inthread2  
  11. {  
  12. lock($b);#willbeblocked,asalreadylockedbythread1  
  13. sleep(3);#afterthread1quitfromtheblock  
  14. lock($a);#deadlockhere  
  15. }  
  16.  

 死锁常常是多Perl线程程序中最隐蔽的问题,往往难以发现与调试,也增加了排查问题的难度。为了避免在程序中死锁的问题,在程序中我们应该尽量避免同时获取多个共享变量的锁,如果无法避免,那么一是要尽量使用相同的顺序来获取多个共享变量的锁,另外也要尽可能地细化上锁的粒度,减少上锁的时间。#p#

信号量

Thread::Semaphore包为Perl线程提供了信号量的支持。你可以创建一个自己的信号量,并通过down操作和up操作来实现对资源的同步访问。实际上,down操作和up操作对应的就是我们所熟知的P操作和V操作。从内部实现上看,Thread::Semaphore本质上就是加了锁的共享变量,无非是把这个加了锁的共享变量封装成了一个Perl线程安全的包而已。由于信号量不必与任何变量绑定,因此,它非常灵活,可以用来控制你想同步的任何数据结构和程序行为。例如

清单13.Perl线程中的信号量    
 

  1. usethreads;  
  2. usethreads::shared;  
  3. useThread::Semaphore;  
  4.  
  5. my$s=Thread::Semaphore->new();  
  6. $s->down();#Poperation  
  7. ...  
  8. $s->up();#Voperation  
  9.  

 从本质上说,信号量是一个共享的整型变量的引用。默认情况下,它的初始值为1,down操作使它的值减1,up操作使它的值加1。当然,你也可以自定义信号量初始值和每次up或down操作时信号量的变化。

Perl线程队列

Thread::Queue包为Perl线程提供了Perl线程安全的队列支持。与信号量类似,从内部实现上看,Thread::Queue也是把一个通过锁机制实现同步访问的共享队列封装成了一个Perl线程安全的包,并提供统一的使用接口。Thread::Queue在某些情况下可以大大简化Perl线程间通信的难度和成本。例如在生产者-消费者模型中,生产者可以不断地在Perl线程队列上做enqueue操作,而消费者只需要不断地在Perl线程队列上做dequeue操作,这就很简单地实现了生产者和消费者之间同步的问题。

其他有用的非核心包

本文前面讨论的所有内容都在Perl线程核心包的范畴之内。其实CPAN上还有其他一些与Perl线程相关的非核心包,它们往往也会给Perl线程的使用带来很大的便利,这里我们选出两个稍加介绍,抛砖引玉。

Thread::Pool包允许你在程序中创建一批Perl线程去完成多个类似的任务。例如当你希望创建一个多Perl线程程序去完成检验1000个ip地址是否都能ping通的任务时,Thread::Pool包可以给你带来便利。
Thread::RWLock包为Perl线程中的读写操作提供了锁机制的支持。例如当你有多个reader和writerPerl线程共同访问某一个或几个文件时,Thread::RWLock包可以给你带来便利。

总结

本文主要介绍了Perl中Perl线程的使用方法,包括Perl线程的创建、执行与消亡,如何在Perl线程中使用共享变量并通过锁机制、信号量和Perl线程队列的方法来实现Perl线程间的同步。PerlithreadsPerl线程模型与主流Perl线程模型***的不同之处在于默认情况下任何数据结构都是非共享的,或者说Perl中的ithreads是一个“非轻量级”的Perl线程模型。虽然这样的Perl线程模型增加了程序的开销,但它并不会在Perl线程的功能性上打折扣,同时它也使得Perl线程间的通讯和共享变得更加简单。这也符合了Perl一贯的简单而强大的理念和原则。

【编辑推荐】

  1. Perl线程的生命周期
  2. 追溯Perl线程的历史
  3. Perl二维数组用法全程剖析
  4. 浅析Perl面向对象编程用法
  5. Perl正则表达式语法解析
责任编辑:佚名 来源: csdn.net
相关推荐

2010-07-14 10:48:37

Perl线程

2009-06-18 13:32:39

Java线程生命周期

2012-01-16 09:00:56

线程

2009-06-29 18:03:15

Java多线程线程的生命周期

2023-10-26 08:25:35

Java线程周期

2010-07-28 12:47:06

Flex组件

2015-07-08 16:28:23

weak生命周期

2022-04-19 07:20:24

软件开发安全生命周期SSDLC应用安全

2009-06-11 11:28:35

JSF生命周期

2021-08-24 07:53:28

AndroidActivity生命周期

2011-06-16 09:31:21

ActivityAndroid

2012-04-28 13:23:12

Java生命周期

2020-03-30 13:20:58

线程Java编程语言

2019-10-16 10:50:13

Linux内核测试

2009-06-17 15:06:50

Hibernate实体

2013-07-29 05:11:38

iOS开发iOS开发学习类的'生命周期'

2021-07-19 05:52:29

网络生命周期网络框架

2013-08-19 17:03:00

.Net生命周期对象

2009-06-24 10:47:55

JSF生命周期

2012-06-20 10:29:16

敏捷开发
点赞
收藏

51CTO技术栈公众号