Welcome to jaever.com/diary

[转载]PERL进程、管道、信号

PERL灵活的进程函数是为了复制进程用于分担任务与程序的工作量。

PERL中复制进程有两种方法:fork()、system()与exec()。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

fork()部分:*NIX传统的复制进程方法

==============================================================

fork()函数:

作用:进程复制函数。

用法:$pid=fork();

讲解:

无参数;当本进程为父进程时返回值为子进程的PID值,当进程为子进程时返回值为0。

实例:

#!usr/bin/perl -w

$pid=fork(); #复制进程,并把返回值附入$pid

die "Error:$!\n" unless defined $pid; #制定程序的错误机制,此步可略

if($pid!=0){ #条件选择,测试$pid值

print"This is a main pid!PID is $$!\n"; #$pid值不等于0,此为父进程(附:$$为保留变量,其值为此进程的PID)

}else{ #否则.....

print"This is a sub pid!PID is $$!\n"; #$pid值为0,此为子进程

}

exit 1; #退出程序

分析实例:

楼上的程序没有父进程与子进程的明显分化,要将它们分开就要靠测试$pid的值,所以对fork()函数的调用来说条件语句是非常重要的,需要通过它们来辨别fork() 的返回值。

±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±

getppid()函数:

作用:在子进程中调用此函数来获得父进程PID值。

用法:$parent=getppid();

讲解:无参数,调用后其返回值为父进程的PID值。

实例:

#!usr/bin/perl -w

$pid=fork(); #复制进程

die "Error:$!\n" unless defined $pid; #制定错误机制,此步可略

if($pid==0){ #当进程为子进程则进入条件,当进程为父进程则跳过到程序结束

$parent=getppid(); #通过getppid()得到父进程PID值

print"This is a sub pid:$$,the parent is $parent\n"; #在STDOUT打印子进程PID值与其父进程ID值

}

exit 1; #退出程序

注意:楼上的getppid()实例无法在WIN32下通过,建议使用*nix平台。

±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±

关于使用fork():通过fork()创建的子进程共享了父进程的所有变量、句柄等当前值。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

system()与exec()部分:更直观的进程调用

=============================================================

system()函数:

作用:直接生成子进程。

用法:$result=system("dir/w *.bat"); 或 $result=system("dir/w","*.bat");

讲解:参数为SHELL语句。当函数能正常调用时返回值为0(注意:此与其他函数不一致),其他返回值均为错误。

实例:

#!usr/bin/perl -w

print STDOUT system("dir/w","*.pl"); #把system()函数中的子进程SHELL语句"dir/w *.pl"的结果输出到STDOUT中

exit 1; #退出程序

#在c:\根目录下运行结果为:

C:\>perl mm.pl

驱动器 C 中的卷没有标签。

卷的序列号是 2629-08EF

C:\ 的目录

aaa.pl bbb.pl zzz.pl xxx.pl SOCK.PL

connect.pl connect2.pl connect3.pl connect4.pl connect5.pl

connect6.pl connect7.pl udpc.pl udps.pl connect8.pl

connect10.pl fork.pl pidd.pl mm.pl

19 个文件 7,503 字节

0 个目录 5,514,014,720 可用字节

0

#注意楼上最后的"0",这就是返回后的数值,楼上表示程序正常调用了system()函数中的shell语句了。  

±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±

exec()函数:

作用:以指定的SHELL语句代替原进程。

用法:$result=exec("copy *.bat c:\"); 或 $result=exec("copy","*.bat","c:\");

讲解:参数为SHELL语句,成功调用后返回值为undef,其他返回值均为失败。使用此函数后生成的新进程与原进程为同一进程,

有相同的PID,共享变量语柄等一切当前值。

实例与system()相当,所以不作讨论了。

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

附:关于"Perl的管道"部分内容博大精深,而本人又水平有限,所以只好草草了事,如果有哪里不妥还望各位前辈指点

管道是为了使不同进程可以进行通信的制定的。管道是*NIX编程的重点。

与其相关的函数有:open()、pipe()等等。

open():作打开句柄用。

格式:open(FILEHANDLE,"符号+参数");

例子:open(NIX,"|wc -lw"); #打开名为NIX的管道,其进程为‘wc -lw’,管道为写入。

open(DDD,"dir c:\|"); #打开名为DDD的管道,其进程为‘dir c:\’,管道为读取。

讲解:FILEHANDLE(句柄)包括很多成分,如文件句柄、SOCKET句柄、管道句柄,此文只谈到管道句柄。

第二个参数为双引号或单引号相括着的管道符号与参数。管道符号为"|",把管道符号放到参数的左边为‘只读’,放到右边为‘只写’,如果两边都有便为双向管道(既可读也可写)。

简单的管道实例:

#!usr/bin/perl -w

open(AAA,"dir d:|"); #打开管道AAA,进程为"dir d:",只读

@bbb=<AAA>; #从管道中读取内容,并压入@bbb数组

print"@bbb\n"; #把@bbb数组全部输出到STDOUT

close AAA; #关闭管道AAA

exit 1; #退出程序

〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓

pipe():创建管道对。

格式: pipe(READ,WRITE);

实例:pipe(README,WRITEME); #创建了一个管道对,"README"用于读,"WRITEME"用于写。

$aaa=pipe(AAA,BBB); #创建了一个管道对,"AAA"用于读,"BBB"用于写,$aaa变量为调用pipe()的返回值。

讲解:正常调用后返回值为非零数,第一个参数为被创建的读管道,第二个参数为被创建的写管道。此函数通常配合进程中

的fork()函数一同使用,步骤是先使用pipe()函数建立管道对,再使用fork()创建新进程,在不同的进程关闭不同的

管道,这样就可以达到管道间通信的目的了。

〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓〓

close():关闭管道

格式: close(AAA);

close BBB;

实例与格式相当,也就不详细介绍了。

讲解:close()在调用时能将子程序的终止代码放到特殊变量$?中;当关闭的是写管道时close()调用将进入堵塞状态直至另一

端完成它的全部工作为止。

信号其实就是编程里俗称的中断,它使监视与控制其他进程变为有可能。

首先说说通用信号,通用信号归纳起来可以组成以下列表:

=============================================================

信号名 值 标注 解释

------------------------------------------------------------------------

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-----不能截取或忽略进程信号

=============================================================

下面就以INT作范例演示一下调用过程吧:

#!usr/bin/perl -w

#c:\test11.pl

my $aaa=0; #对计数器变量$aaa进行负值

while($aaa<3){ #进入循环体

print"Begin\n"; #打印字符串到STDOUT

sleep(5); #睡眠函数,参数为5秒

next unless $SIG{INT}=\&demon; #选择结构,demon子程序值负于中断函数

}

sub demon{ #demon子程序体

$aaa++; #计数器自加

print"Stop!\n"; #打印字符串到STDOUT

}

exit 1; #退出程序

输出结果:在SHELL里不停的打印出"Begin"字样,相隔5秒,一但在键盘中执行程序

中断操作(Control+"c"),屏幕就会打印出"Stop!"字样,不停地继续下去。

中断调用总结:调用需要使用到系统保留全局HASH数组%SIG,即使用"$SIG{信号名}"

截取信号,截取后将其负某个代码(子函数)的地址值,这代码就是截

取后要执行的结果了。

INFO: 2008-07-30 09:40:29 | purpen | digg | link

Copyright © 2008 Jaever. All rights reserved.

This Site looks and works best when viewed using browsers enabled with JavaScript 1.5 and CSS, such as Firefox 1+ or Safari 3+.