Perl - 第二十六章 | Perl 進程管理
Perl 中你可以以不同的方法來創建進程。
- 你可以使用特殊變量 $$ 或 $PROCESS_ID 來獲取進程 ID。
- %ENV 哈希存放了父進程,也就是shell中的環境變量,在Perl中可以修改這些變量。
- exit() 通常用於退出子進程,主進程在子進程全部退出後再退出。
- 所有打開的句柄會在子程序中被 dup() 函數複製,所有關閉進程所有句柄不會影響其他進程。
反引號運算符
使用反引號運算符可以很容易的執行 Unix 命令。你可以在反引號中插入一些簡單的命令。命令執行後將返回結果:
1 2 3 4 5 6 7 8 9
|
@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
|
$PATH = "我是 Perl 的變量";
system('echo $PATH'); system("echo $PATH"); 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
|
if(!defined($pid = fork())) { 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
|
local $SIG{CHLD} = "IGNORE"; if(!defined($pid = fork())) { 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
|
kill('INT', 104, 102); 1;
|
註:以上參考了
Tutorialspoint, Perl - Process Management