Perl-进程管理4

1. 用fork开展地下工作

除了之前介绍的高级接口外,perl还提供了近乎直接执行unix及某些其它系统的低级进程管理系统调用的能力
system 'date;'的低级系统调用,大概可以写成

defined(my $pid = fork) or die "Cannot fork: $!";
unless($pid){
	# 能运行到这里的是子进程
	exec 'date';
	die "cannot exec date: $!";
}
# 能运行到这里的是父进程
waitpid($pid, 0);

这里检查了fork的返回值,它在失败时会返回undef。只有父进程中返回的$pid不是0,所以只有子进程才会执行条件语块中的exec函数,父进程会略过该部分,直接执行waitpid函数,并在那里一直等待,直到它派生出的子进程结束(在这期间,如果其它的子进程结束执行,则会被忽略掉)

虽然这样看起来很麻烦,不过程序员也获得了最大控制权,可以创建任意管道、对文件句柄进行处理,也可以进一步了解子进程ID和父进程ID

2. 发送和接收信号

unix信号一般有:SIGHUP、SIGCONT、SIGINT和一个虚拟的零信号SIGZERO
windows实现的是POSIX信号体系的一个子集

信号会用不同的名称相互区分(像SIGINT代表中断信号),另外还有一个相关的整数也可用来识别(它的取值范围从1到16、1到32或1到63,具体得看自己的unix系统)。一般某个重大事件发生时就会发出信号,比如在终端上按下Control+C这样的中断组合键,就会给与此终端相连的所有进程发送SIGINT信号。某些信号可能时由系统自动发送的,但也可能来自别的进程

可以从perl进程发送信号给别的进程,不过需要先知道目标进程的编号

kill 2, 4201 or die "Cannot signal 4201 with SIGINT: $!";
kill 'INT', 4021 or die "Cannot signal 4201 with SIGINT: $!";
kill INT => 4201 or die "Cannot signal 4201 with SIGINT: $!";

发送信号的命令取名为kill,因为发明信号的主要目的之一就是中止运行了太久的进程

在unix系统上,可以用kill命令来列出所有信号的数字编号

$ kill -l 2 # INT
$ kill -l INT # 2

如果-l参数后不加任何内容,则列出所有信号名称和编号

如果要中断的进程早已退出,或者是别人启动的进程,就会得到失败的返回值

可以借助这点来判断某个进程是否还或者,有一个特殊的信号,编号为0,它的意思是“只是检查一下是否可以向这个进程发送信号,但我现在还不想发送信号给它,所以不要真的发送任何东西去烦它”

unless(kill 0, $pid){
	warn "$pid has gone away!":
}
my $temp_directory = '/tmp/myprog.$$'; # 在这个目录下创建文件
mkdir $temp_directory, 0700 or die "Cannot create $temp_directory: $!";

sub clean_up{
	unlink glob "$temp_directory/*";
	rmdir $temp_directory;
}

sub my_int_handler{
	&clean_up();
	die "interrupted, exiting...\n";
}

$SIG{'INT'} = 'my_int_handler';
...;
# 此处是某些无关信号工作的代码
# 时间流逝,程序在运行着,在临时目录中创建一下
# 文件仍在临时目录中,但有人按下了Control+C意图中断
...;
# 如果没有收到中断,将会运行到此处,完成善后清理工作
&clean_up();

随perl一同发布的File::Temp模块可以自动清理它所创建的临时文件或目录

对特殊哈希%SIG赋值就能设置收到信号时自动调用的善后子程序

假如信号处理子程序没有结束程序而是直接返回,那么程序会从先前中断的地方继续执行。如果该信号只是要中断并处理某些事情,而不是停止整个程序的话,这时就该用返回而非退出

比如,假如处理文件里的每行都慢到要花几秒钟的时间,而你想要在收到信号时停止处理,却不想让进行中的这一行中断,这时,只要在信号处理子程序中设定一个标记,然后再每行处理结束时检查它即可

my $int_flsg = 0;
$SIG{'INT'} = 'my_int_handler';
sub my_int_handler {$int_flag =1;}

while(...处理某些事务...){
	last if $int_flag;
	...
}

exit();

大部分时候,perl会一直等到安全的时机,才会动手处理进来的信号
比如perl在分配内存和调整内部数据结构的阶段是不会理睬大多数的信号的,不过perl会立即处理SIGILL、SIGBUS,还有SIGSEGV这些信号,所以对程序运行来说,这些信号可能会有安全隐患

你可能感兴趣的:(perl,开发语言,unix)