Like Share Discussion Bookmark Smile

J.J. Huang   2021-06-16   Perl   瀏覽次數:

Perl - 第二十六章 | Perl 進程管理

Perl 中你可以以不同的方法來創建進程。

  • 你可以使用特殊變量 $$ 或 $PROCESS_ID 來獲取進程 ID。
  • %ENV 哈希存放了父進程,也就是shell中的環境變量,在Perl中可以修改這些變量。
  • exit() 通常用於退出子進程,主進程在子進程全部退出後再退出。
  • 所有打開的句柄會在子程序中被 dup() 函數複製,所有關閉進程所有句柄不會影響其他進程。

反引號運算符

使用反引號運算符可以很容易的執行 Unix 命令。你可以在反引號中插入一些簡單的命令。命令執行後將返回結果:

1
2
3
4
5
6
7
8
9
#!/usr/bin/perl

@files = `ls -l`;

foreach $file (@files){
print $file;
}

1;

執行以上程序,輸出結果為:

1
2
3
4
5
6
7
total 48
-rwxr-xr-x@ 1 morose staff 759 6 9 12:20 Employee.pm
-rwxr-xr-x@ 1 morose staff 594 6 9 11:03 Person.pm
-rwxrwxr-x@ 1 morose staff 153 4 1 11:43 T.pm
-rwxr-xr-x@ 1 morose staff 359 6 9 12:21 employee.pl
-rwxrwxr-x@ 1 morose staff 81 6 15 20:34 main.pl
-rwxr-xr-x 1 morose staff 381 4 1 16:25 redis.js

system() 函數

你也可以使用 system() 函數執行 Unix 命令,執行該命令將直接輸出結果。默認情況下會送到目前Perl的STDOUT指向的地方,一般是屏幕。你也可以使用重定向運算符 > 輸出到指定文件:

1
2
3
4
5
6
7
total 48
-rwxr-xr-x@ 1 morose staff 759 6 9 12:20 Employee.pm
-rwxr-xr-x@ 1 morose staff 594 6 9 11:03 Person.pm
-rwxrwxr-x@ 1 morose staff 153 4 1 11:43 T.pm
-rwxr-xr-x@ 1 morose staff 359 6 9 12:21 employee.pl
-rwxrwxr-x@ 1 morose staff 81 6 15 20:34 main.pl
-rwxr-xr-x 1 morose staff 381 4 1 16:25 redis.js

你需要注意命令包含環境變量如 $PATH 或 $HOME的輸出結果,如下所示:

1
2
3
4
5
6
7
8
9
#!/usr/bin/perl

$PATH = "我是 Perl 的變量";

system('echo $PATH'); # $PATH 作為 shell 環境變量
system("echo $PATH"); # $PATH 作為 Perl 的變量
system("echo \$PATH"); # 轉義 $

1;

執行以上程序,輸出結果如下:

1
2
3
/usr/local/opt/sqlite/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/share/dotnet:~/.dotnet/tools:/Library/Apple/usr/bin:/Library/Frameworks/Mono.framework/Versions/Current/Commands:/Users/morose/go:/Users/morose/go/bin:
我是 Perl 的變量
/usr/local/opt/sqlite/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/share/dotnet:~/.dotnet/tools:/Library/Apple/usr/bin:/Library/Frameworks/Mono.framework/Versions/Current/Commands:/Users/morose/go:/Users/morose/go/bin:

fork() 函數

Perl fork() 函數用於創建一個新進程。
在父進程中返回子進程的PID,在子進程中返回0。如果發生錯誤(比如,內存不足)返回undef,並將$!設為對應的錯誤信息。
fork 可以和 exec 配合使用。exec 函數執行完引號中的命令後進程即結束。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/usr/bin/perl

if(!defined($pid = fork())) {
# fork 發生錯誤返回 undef
die "無法創建子進程: $!";
}elsif ($pid == 0) {
print "通過子進程輸出\n";
exec("date") || die "無法輸出日期: $!";

} else {
# 在父進程中
print "通過父進程輸出\n";
$ret = waitpid($pid, 0);
print "完成的進程ID: $ret\n";

}

1;

執行以上程序,輸出結果如下:

1
2
3
4
通過父進程輸出
通過子進程輸出
2021年 6月16日 週二 09時00分00秒 CST
完成的進程ID: 66994

如果進程退出時,會向父進程發送一個CHLD的信號後,就會變成僵死的進程,需要父進程使用wait和waitpid來終止。當然,也可以設置$SIG{CHLD}為IGNORG:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/usr/bin/perl

local $SIG{CHLD} = "IGNORE";

if(!defined($pid = fork())) {
# fork 發生錯誤返回 undef
die "無法創建子進程: $!";
}elsif ($pid == 0) {
print "通過子進程輸出\n";
exec("date") || die "無法輸出日期: $!";

} else {
# 在父進程中
print "通過父進程輸出\n";
$ret = waitpid($pid, 0);
print "完成的進程ID: $ret\n";

}

1;

執行以上程序,輸出結果如下:

1
2
3
4
通過父進程輸出
通過子進程輸出
2021年 6月16日 週二 09時01分00秒 CST
完成的進程ID: -1

Kill 函數

Perl kill(‘signal’, (Process List))給一組進程發送信號。signal是發送的數字信號,9為殺掉進程。

首先看看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輸出

以下範例向進程 104 和 102 發送 SIGINT 信號:

1
2
3
4
5
#!/usr/bin/perl

kill('INT', 104, 102);

1;

註:以上參考了
Tutorialspoint, Perl - Process Management