perl 的linux信号处理,perl 信号处理

转载文章请注明,转载自:扶凯[]

本文链接:

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程序中出现这个信号时,执行我们自己定义某段代码(子函数)的地址值(定义信号响应函数),这代码就是截取这个信息后要执行的结果了。

例如:

#!/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块中

#!/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来处理会更加容易些

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

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都无所谓.

当然先排除自己

{ local $SIG{HUP} = 'IGNORE'; # 排除自己\ kill(HUP,-$$); #通知自己的进程组 }

Fork所做的事情

父进程将代码段,堆栈段,数据段完全复制一份给子进程。也就是说,在子进程运行之初,它拥有父进程的一切变量和句柄。例如,父进程申明了某个hash表,那这个hash表也会被子进程拥有。

然而,一旦子进程开始运行,它的数据段和堆栈段就在内存里完全和父进程分离开了。也就是说,两个进程间不再共享任何数据。例如前面所说的hash表,虽然子进程从父进程处继承了这个数据结构,但子进程写往hash里的数据,不会被父进程访问到。

Fork出来的僵死进程

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

在 Unix 系统上守护进程化

对于 Fork  出来的程序,我们常常需要给进程推到后台,不然在前台程序会一直占用,当关掉当前 shell 时,程序就退出了。如下有个 <>中一个非常合适的例子:

#!/usr/bin/perl

use strict;

use POSIX qw(setsid);

nohup(@ARGV);

sub nohup {

my $child = fork();

die $! unless defined $child;

exit 0 if $child;

setsid();

open (STDIN, ", "/dev/null");

open (STDOUT, ">", "nohup.out");

open (STDERR, ">&", STDOUT);

exec "@_";

}

sub daemonStart {

die "Can't fork:$!" unless defined (my $child = fork);

exit 0 if $child;

open STDIN, "/dev/null" or die "Can't write to /dev/null: $!";

#open STDERR, ">&STDOUT" || die ("open STDERR failed");

# 分离终端和进程组

setsid() or die "Can't start a new session.";

chdir '/'; #修改工作目录

umask(0); #设置文件的 umask

$ENV{PATH} = "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin";

return $$;

建议使用 Proc::Daemon 模块

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值