Perl中对信号和并发的处理

Perl中对信号和并发的处理

Jun 9th, 2009

转载本站文章请注明,转载自:扶凯[http://www.php-oa.com]

本文链接: http://www.php-oa.com/2009/06/09/perl_signal.html

linux中的信号
先了解在linux中的信号,信号其实就是编程里俗称的中断,它使监视与控制其他进程变为有可能。中断信号(signal,又简称为信号)用来通知进程发生了异步事件。进程之间可以互相通过系统调用kill发送软中断信号。内核也可以因为内部事件而给进程发送信号,通知进程发生了某个事件。注意,信号只是用来通知某进程发生了什么事件,并不给该进程传递任何数据。

首先看看linux中的常用信号,见如下列表:
========================================================================
信号名          值          标注          解释
————————————————————————
HUP             1           A             检测到挂起
INT             2           A             来自键盘的中断
QUIT            3           A             来自键盘的停止
ILL             4           A             非法指令
ABRT            6           C             失败
FPE             8           C             浮点异常
KILL            9           AF            终端信号
USR1            10          A             用户定义的信号1
SEGV            11          C             非法内存访问
USR2            12          A             用户定义的信号2
PIPE            13          A             写往没有读取者的管道
ALRM            14          A             来自闹钟的定时器信号
TERM            15          A             终端信号
CHLD            17          B             子进程终止
CONT            18          E             如果被停止则继续
STOP            19          DF            停止进程
TSTP            20          D             tty键入的停止命令
TTIN            21          D             对后台进程的tty输入
TTOU            22          D             对后台进程的tty输出
————————————————————————
著明:上表中‘值’列下没有列出的值所对应的信号为系统调用的非标准信号。上表中的第三列‘标注’定义了当进程接受到信号后的默认的操作
        A—–终止进程
        B—–忽略进程信号
        C—–终止进程并卸下内核
        D—–停止进程
        E—–恢复进程
        F—–不能截取或忽略进程信号
========================================================================

Perl中命令信号的原理
Perl 提供了%SIG 这个特殊的默认HASH.调用需要使用到系统保留全局HASH数组%SIG,即使用’$SIG{信号名}’截取信号,相当于,在perl程序中出现这个信号时,执行我们自己定义某段代码(子函数)的地址值(定义信号响应函数),这代码就是截取这个信息后要执行的结果了。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
#!/usr/bin/perl
$SIG{TERM} = $SIG{INT} =/&yoursub;
my $i = 1;
while(1){
        sleep 1;
        $i = $i +1;
        print $i."/n";
}
sub yoursub{
        print " exit ... /n";
        exit
}

最程序运行前,我们给$SIG{TERM}和$SIG{INT}二个hash放一个子函数的引用(地址),当有终端信号或来自键盘的中断时,上面的while中的就不在运行,就开始运行yoursub这个函数.

可以使用的地方

象对信息的处理,我们常用到的地方,可以捕捉die及一些warning的信息,然后打印出来,我们也可以让程序在退出来之前,就是按下Ctrl+c时,进行一些任务(如删除tmp文件),需要注意的地方是.为了尽可能早的加载这些代码,这样就能保证程序一执行就能先得到信号。 这样用处非常大,比如我们写的perl的CGI.可以用信号来捕捉CGI程序Internal 500 错误,不然出现了问题,大多数都必须查看Web server的日志才能知道程序哪里出了错误,页面只一个500服务器错误,象php因为是mod,直接就显示在网页上。 可以使用如下的方法.比如将信号捕捉代码放到BEGIN块中

1
2
3
4
5
6
7
8
9
10
11
#!/usr/bin/perl
use strict;
BEGIN {
     # fatal handler setting.
     $SIG{__DIE__} = $SIG{__WARN__} = /&handler_fatal;
}
 
sub handler_fatal {
print  "Content-type: text/html/n";
print  "@_&";
}

当然perl的CGI的500错误,用下面的模块CGI::Carp来处理会更加容易些

1
2
use CGI::Carp qw(fatalsToBrowser);
die  'Bad error here';

另一个常用的用法使用$SIG{ALRM},设置等待超时一般都这样做:

1
2
3
4
5
6
7
local $SIG{ALRM} = sub { alarm 0;die "TIMEOUT"; };#超时处理过程
eval {
  alarm(10);   #设定10秒钟后如果下面的代码没处理完,则进入超时处理过程
 $input = <>;   #处理过程
  alarm(0);    #如果处理完了,取消超时处理设置   
};
if ($@ =~ /TIMEOUT/) { ... }

注意这里alarm(10)一定要放在eval内。否则,万一程序执行完alarm后发生任务切换,而程序再次获得时间片时,ALRM信号已经发生, 这时程序还没有执行到eval内就产生die,程序就会退出
 

 

有时我们要杀死所有的子进行,需要用到向进程组发送信息

在perl中,进程组的ID就是$$.如果程序想给所有由它启动的所有子进程发送一个挂起的信号号,现实的方法,先调用setpgrp(0,0),使自己成为新的进程组的领头.这样不管是fork还是open,还是system都无所谓.

当然先排除自己

1
2
3
4
{
   local $SIG{HUP} = 'IGNORE'; # 排除自己/
   kill(HUP,-$$);                        #通知自己的进程组<p> </p>
}

Fork所做的事情

父进程将代码段,堆栈段,数据段完全复制一份给子进程。也就是说,在子进程运行之初,它拥有父进程的一切变量和句柄。例如,父进程申明了某个hash表,那这个hash表也会被子进程拥有。
然而,一旦子进程开始运行,它的数据段和堆栈段就在内存里完全和父进程分离开了。也就是说,两个进程间不再共享任何数据。例如前面所说的hash表,虽然子进程从父进程处继承了这个数据结构,但子进程写往hash里的数据,不会被父进程访问到。

Fork出来的僵死进程

如果进程退出时,会向父发送一个CHLD的信号后,就会变成僵死的进程,需要父进程使用wait和waitpid来收割.当然,也可以设置$SIG{CHLD}为IGNORG

不错的Fork的模块

1
2
3
4
5
6
7
8
use Parallel::ForkManager;
$pm = new Parallel::ForkManager($MAX_PROCESSES)#标明最大进程数。0 是不 fork .
foreach $data (@all_data) {
my $pid = $pm->start and next;     # $pm->start 来开始 fork.$pm 是子进程时返回 0 ,父进程时返回子进程的进程.&ldquo;and next&rdquo; 用来跳过父进程。
...子进程中...
$pm->finish;  #结束子程序
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值