本文和大家重点讨论一下Perl线程的生命周期,主要包括创建Perl线程,join方法和detach方法两大部分内容,希望通过本文的介绍你对Perl线程的生命周期有一定的认识。
Perl线程的生命周期
创建Perl线程
Perl线程作为Perl中的一种实体,其一生可以粗略的分为创建,运行与退出这三个阶段。创建使得Perl线程从无到有,运行则是Perl线程完成其主要工作的阶段,退出自然就是指Perl线程的消亡。Perl线程的运行和普通函数的执行非常类似,有其入口参数,一段特定的代码流程以及执行完毕后返回的一个或一组结果,唯一与普通函数调用的不同之处就在于新建Perl线程的执行与当前Perl线程的执行是并行的。
Perl里创建一个新的Perl线程非常简单,主要有两种方法,他们分别是:
使用threads包的create()方法,例如
清单3.通过create()方法创建Perl线程
use threads;
sub say_hello {
printf("Hellothread!@_.\n");
return(rand(10));
}
my$t1=threads->create(\&say_hello,"param1","param2");
my$t2=threads->create("say_hello","param3","param4");
my$t3=threads->create(
sub{
printf("Hellothread!@_\n");
return(rand(10));
}, "param5", "param6");
使用async{}块创建Perl线程,例如
清单4.通过async{}块创建Perl线程
#!/usr/bin/perl #
use threads;
my $t4=async{
printf("Hellothread!\n");
};
join方法和detach方法
Perl线程一旦被成功创建,它就立刻开始运行了,这个时候你面临两种选择,分别是join或者detach这个新建Perl线程。当然你也可以什么都不做,不过这可不是一个好习惯,后面我们会解释这是为什么。
我们先来看看join方法,这也许是大多数情况下你想要的。从字面上来理解,join就是把新创建的Perl线程结合到当前的主Perl线程中来,把它当成是主Perl线程的一部分,使他们合二为一。join会触发两个动作,首先,主Perl线程会索取新建Perl线程执行结束以后的返回值;其次,新建Perl线程在执行完毕并返回结果以后会自动释放它自己所占用的系统资源。例如
清单5.使用join()方法收割新建Perl线程
#!/usr/bin/perl #
use threads;
sub func{
sleep(1);
return(rand(10)); #return (int(rand(10)));
}
my$t1=threads->create(\&func);
my$t2=threads->create(\&func);
printf("dosomethinginthemainthread\n");
my$t1_res=$t1->join();
my$t2_res=$t2->join();
printf("t1_res=$t1_res\nt2_res=$t2_res\n");
由此我们不难发现,调用join的时机是一个十分有趣的问题。如果调用join方法太早,新建Perl线程尚未执行完毕,自然就无法返回任何结果,那么这个时候,主Perl线程就不得不被阻塞,直到新建Perl线程执行完毕之后,才能获得返回值,然后资源会被释放,join才能结束,这在很大程度上破话了Perl线程之间的并行性。相反,如果调用join方法太晚,新建Perl线程早已执行完毕,由于一直没有机会返回结果,它所占用的资源就一直无法得到释放,直到被join为止,这在很大程度上浪费了宝贵的系统资源。因此,join新建Perl线程的最好时机应该是在它刚刚执行完毕的时候,这样既不会阻塞当前Perl线程的执行,又可以及时释放新建Perl线程所占用的系统资源。
我们再来看看detach方法,这也许是最省心省力的处理方法了。从字面上来理解,detach就是把新创建的Perl线程与当前的主Perl线程剥离开来,让它从此和主Perl线程无关。当你使用detach方法的时候,表明主Perl线程并不关心新建Perl线程执行以后返回的结果,新建Perl线程执行完毕后Perl会自动释放它所占用的资源。
一个新建Perl线程一旦被detach以后,就无法再join了。当你使用detach方法剥离Perl线程的时候,有一点需要特别注意,那就是你需要保证被创建的Perl线程先于主Perl线程结束,否则你创建的Perl线程会被迫结束,除非这种结果正是你想要的,否则这也许会造成异常情况的出现,并增加程序调试的难度。
本节的开始我们提到,新Perl线程被创建以后,如果既不join,也不detach不是一个好习惯,这是因为除非明确地调用detach方法剥离Perl线程,Perl会认为你也许要在将来的某一个时间点调用join,所以新建Perl线程的返回值会一直被保存在内存中以备不时之需,它所占用的系统资源也一直不会得到释放。然而实际上,你打算什么也不做,因此宝贵的系统资源直到整个Perl应用结束时才被释放。同时,由于你即没有调用join有没有调用detach,应用结束时Perl还会返回给你一个Perl线程非正常结束的警告。
Perl线程的消亡
大多数情况下,你希望你创建的Perl线程正常退出,这就意味着Perl线程所对应的函数体在执行完毕后返回并释放资源。例如在清单5的示例中,新建Perl线程被join以后的退出过程。可是,如果由于detach不当或者由于主线因某些意外的异常提前结束了,尽管它所创建的Perl线程可能尚未执行完毕,但是他们还是会被强制中止,正所谓皮之不存,毛将焉附。这时你也许会得到一个类似于“Perlexitedwithactivethreads”的警告。
当然,你也可以显示地调用exit()方法来结束一个Perl线程,不过值得注意的是,默认情况下,如果你在一个Perl线程中调用了exit()方法,其他Perl线程都会随之一起结束,在很多情况下,这也许不是你想要的,如果你希望exit()方法只在调用它的Perl线程内生效,那么你在创建该Perl线程的时候就需要设置’exit’=>’thread_only’。例如
清单7.为某个Perl线程设置’exit’=>’thread_only’属性
#!/usr/bin/perl #
use threads;
su bsay_hello{
printf("Hellothread!@_.\n");
sleep(10);
printf("Bye\n");
}
sub quick_exit{
printf("Iwillbeexitinnotime\n");
exit(1);
}
my $t1=threads->create(\&say_hello,"param1","param2");
my $t2=threads->create({'exit'=>'thread_only'},\&quick_exit);
$t1->join();
$t2->join();
如果你希望每个Perl线程的exit方法都只对自己有效,那么在每次创建一个新Perl线程的时候都去要显式设置’exit’=>’thread_only’属性显然有些麻烦,你也可以在引入threads包的时候设置这个属性在全局范围内有效。
分享到:
相关推荐
线程的生命周期包括创建、运行、合并(join)或分离(detach)等几个阶段。 ##### 1. 创建线程 - **方法**:使用`threads`模块的`create()`或`new()`方法。 - **示例**:`my $thread = threads->create(\&my_function, ...
1. **Perl运行时嵌入(Perl Run-Time Embedding)**: mod_perl使得Perl解释器成为Apache的一部分,这样Perl代码在服务器启动时加载,并在整个服务器生命周期内驻留,避免了每次请求时重新解析和编译Perl脚本的时间。...
3. **事件的生命周期**: 事件可以是一次性的,也可以是周期性的。一次性事件只触发一次,而周期性事件会按照设定的间隔反复触发。这通过在创建事件时设置适当的参数来实现。 4. **处理事件**: 当事件触发时,其...
理解线程的创建、同步、通信以及生命周期管理是Java开发者必备的技能。 线程的创建可以通过实现Runnable接口或者继承Thread类来实现。通过Runnable接口,多个线程可以共享同一个目标对象,而通过Thread类则可以直接...
iRODS是一种开源的数据管理和存储系统,它提供了强大的规则引擎,用于在数据生命周期的不同阶段执行自定义操作,例如数据的自动迁移、复制和权限控制。通过Perl iRODS Wrap,开发者可以利用Perl的灵活性和丰富生态来...
例如,你可以自定义`run`方法来处理每个连接的生命周期,或者通过重写`accept_callback`来实现特定的连接接受逻辑。 在`Net-Server-0.75`这个版本中,可能包含了以下内容: 1. `lib/Net/Server.pm`: 主要的服务器...
5. **生命周期管理**:临时文件和目录的生命周期与它们在代码中的引用密切相关。一旦对象被解除引用,其关联的临时文件或目录就会被删除。这可以通过 Perl 6 的垃圾收集机制实现。 6. **API 使用**:Perl6-Temp-...
- Servlet有更高效的生命周期管理,可以保持状态,而CGI每次请求都会创建新进程,效率较低。 - Servlet支持多线程,可处理并发请求,CGI通常是单线程模型。 - Servlet可以直接访问Web服务器的资源,而CGI相对隔离,...
11. **Servlet生命周期**:Servlet的生命周期包括初始化(init)、服务(service)、销毁(destroy)三个阶段。Servlet和CGI(Common Gateway Interface)的主要区别在于,Servlet是驻留在服务器内存中的,可以处理...
在排错过程中,理解ASP.NET的生命周期、控件事件处理和异常处理机制至关重要。学习如何通过调试工具如Visual Studio来跟踪代码执行,以及使用日志记录和错误捕获技术,可以帮助定位并修复问题。 C#是.NET框架的主要...
首先,Boost库中的智能指针如`shared_ptr`、`unique_ptr`和`weak_ptr`,是C++中管理动态分配对象生命周期的有效工具。它们在C++11标准中被采纳,使得内存管理更加安全和高效,避免了传统裸指针可能导致的悬挂指针和...
通过这个"SD_labs"项目,学习者可以深入理解Perl的实际应用,同时也能了解到软件开发的完整生命周期,包括编码、测试、调试、维护等多个环节。通过研究这个项目,你可以提升Perl编程技能,理解如何将Perl应用于实际...
3. Servlet技术:了解Servlet生命周期,掌握Servlet容器的工作原理。 4. 多线程:为了支持并发访问,需要掌握如何创建和管理线程,处理线程安全问题。 5. 文件系统操作:读取和发送静态文件,需要熟悉Java的文件I/O...
2. **智能指针**:Boost包含几种智能指针,如shared_ptr、unique_ptr和weak_ptr,它们能帮助开发者管理对象的生命周期,防止内存泄漏,是现代C++编程的重要组成部分。 3. **函数对象和绑定**:Boost.Bind和Boost....
这些智能指针管理对象的生命周期,防止内存泄漏,确保了资源的正确释放。 2. **多线程支持**:Boost.Thread提供了C++标准库中没有的线程和同步原语,如线程、条件变量、互斥量和信号量等,帮助开发者构建高效的并发...
1. 智能指针:Boost库提供了shared_ptr、unique_ptr和weak_ptr等智能指针类型,它们可以自动管理对象的生命周期,避免了内存泄漏的问题,同时支持RAII(Resource Acquisition Is Initialization)原则。 2. 多态...
- 线程生命周期 - 同步与锁 - 并发控制工具 8. **高级主题** - Java集合框架 - 泛型与枚举 - Lambda表达式与流API 通过以上这些章节的学习,读者将全面掌握Java语言的关键特性和应用技巧,从而能够自信地...
3. **智能指针(Boost.smart_ptr)**:Boost提供了多种智能指针类型,如`shared_ptr`、`unique_ptr`和`weak_ptr`,它们增强了C++原始指针的功能,自动管理对象的生命周期,防止内存泄漏。 4. **函数对象绑定(Boost...
prefork模型使用单独的进程来处理每个请求,适用于不支持线程安全的环境,配置时需要设置StartServers、MinSpareServers、MaxSpareServers、MaxClients和MaxRequestsPerChild等参数来控制进程的数量和生命周期。...