Perl 进程管理
进程创建
fork 函数
perl
use strict;
use warnings;
my $pid = fork;
if ($pid == 0) {
# 子进程
print "Child process (PID: $$)\n";
sleep 2;
print "Child exiting\n";
exit(0);
} elsif ($pid > 0) {
# 父进程
print "Parent process (PID: $$)\n";
print "Child PID: $pid\n";
waitpid($pid, 0); # 等待子进程结束
print "Child exited\n";
} else {
# fork 失败
die "Cannot fork: $!";
}exec 函数
perl
use strict;
use warnings;
my $pid = fork;
if ($pid == 0) {
# 子进程执行其他程序
exec("ls", "-l") or die "Cannot exec: $!";
# exec 不会返回
} else {
waitpid($pid, 0);
print "Executed command\n";
}system 函数
perl
use strict;
use warnings;
# 执行命令并返回退出状态
my $status = system("ls -l");
if ($status == 0) {
print "Command succeeded\n";
} else {
print "Command failed with status: $status\n";
}
# 使用列表形式(更安全)
my @command = ("ls", "-l", "/tmp");
$status = system(@command);反引号(捕获输出)
perl
use strict;
use warnings;
# 捕获命令输出
my $output = `ls -l`;
print $output;
# 列表形式
my @output = `ls -l`;
print "Lines: " . scalar(@output) . "\n";
# 使用 qx// 操作符
my $output2 = qx/date/;
print $output2;进程通信
管道(Pipe)
perl
use strict;
use warnings;
use IPC::Open2;
# 创建管道
my ($read_fh, $write_fh);
pipe($read_fh, $write_fh) or die "Cannot pipe: $!";
my $pid = fork;
if ($pid == 0) {
# 子进程:写入数据
close($read_fh);
print $write_fh "Hello from child\n";
print $write_fh "Second line\n";
close($write_fh);
exit(0);
} else {
# 父进程:读取数据
close($write_fh);
while (my $line = <$read_fh>) {
print "Parent received: $line";
}
close($read_fh);
waitpid($pid, 0);
}双向管道
perl
use strict;
use warnings;
use IPC::Open2;
my $pid = open2(my $read_fh, my $write_fh, "bc");
# 写入数据
print $write_fh "2 + 2\n";
print $write_fh "10 * 5\n";
print $write_fh "quit\n";
# 读取结果
while (my $line = <$read_fh>) {
print "Result: $line";
}
close($read_fh);
close($write_fh);
waitpid($pid, 0);共享内存
perl
use strict;
use warnings;
use IPC::SysV qw(IPC_PRIVATE IPC_RMID IPC_CREAT S_IRWXU);
use IPC::SharedMem;
# 创建共享内存
my $shm = IPC::SharedMem->new(IPC_PRIVATE, 1024, IPC_CREAT | S_IRWXU)
or die "Cannot create shared memory: $!";
my $pid = fork;
if ($pid == 0) {
# 子进程写入
$shm->write("Hello from child", 0, 20);
sleep 2;
exit(0);
} else {
# 父进程读取
sleep 1;
my $data = $shm->read(0, 20);
print "Parent read: $data\n";
waitpid($pid, 0);
$shm->remove();
}信号量
perl
use strict;
use warnings;
use IPC::Semaphore;
my $sem = IPC::Semaphore->new(1234, 1, IPC_CREAT | 0666)
or die "Cannot create semaphore: $!";
my $pid = fork;
if ($pid == 0) {
# 子进程:获取信号量
$sem->op(0, -1, 0); # 等待并获取
print "Child acquired semaphore\n";
sleep 2;
print "Child releasing semaphore\n";
$sem->op(0, 1, 0); # 释放
exit(0);
} else {
# 父进程:等待子进程完成
waitpid($pid, 0);
print "Parent done\n";
}
$sem->remove();进程控制
wait 和 waitpid
perl
use strict;
use warnings;
my @pids;
# 创建多个子进程
for (1..3) {
my $pid = fork;
if ($pid == 0) {
print "Child $$ running\n";
sleep int(rand(3));
print "Child $$ exiting\n";
exit(0);
} else {
push @pids, $pid;
}
}
# 等待所有子进程
foreach my $pid (@pids) {
my $done_pid = waitpid($pid, 0);
print "Child $done_pid exited\n";
}kill 函数
perl
use strict;
use warnings;
my $pid = fork;
if ($pid == 0) {
# 子进程
$SIG{INT} = sub {
print "Child caught INT signal\n";
exit(0);
};
print "Child running\n";
sleep 10;
print "Child done\n";
} else {
# 父进程
sleep 2;
print "Sending INT to child\n";
kill 'INT', $pid;
waitpid($pid, 0);
print "Child exited\n";
}进程状态检查
perl
use strict;
use warnings;
my $pid = fork;
if ($pid == 0) {
print "Child PID: $$\n";
sleep 5;
exit(0);
} else {
for (1..3) {
sleep 1;
# 检查进程是否还在运行
my $result = kill 0, $pid;
if ($result) {
print "Child $pid is still running\n";
} else {
print "Child $pid has exited\n";
last;
}
}
waitpid($pid, 0);
}信号处理
基本信号处理
perl
use strict;
use warnings;
# 设置信号处理器
$SIG{INT} = sub {
print "\nCaught SIGINT\n";
exit(0);
};
$SIG{TERM} = sub {
print "\nCaught SIGTERM\n";
cleanup();
exit(0);
};
sub cleanup {
print "Cleaning up...\n";
# 清理代码
}
print "Running (press Ctrl+C to stop)\n";
while (1) {
sleep 1;
}忽略信号
perl
use strict;
use warnings;
# 忽略 INT 信号
$SIG{INT} = 'IGNORE';
print "SIGINT ignored (press Ctrl+C won't work)\n";
sleep 10;
print "Done\n";默认信号处理
perl
use strict;
use warnings;
# 使用默认处理
$SIG{INT} = 'DEFAULT';
print "SIGINT using default handler\n";
sleep 10;实践示例
示例 1:进程池
perl
#!/usr/bin/perl
use strict;
use warnings;
sub create_process_pool {
my ($num_workers, $worker_sub) = @_;
my @workers;
for (1..$num_workers) {
my $pid = fork;
if ($pid == 0) {
# 工作进程
while (1) {
$worker_sub->();
}
exit(0);
} else {
push @workers, $pid;
}
}
return \@workers;
}
# 使用
my $workers = create_process_pool(3, sub {
print "Worker $$ processing\n";
sleep 2;
});
# 等待 Ctrl+C
$SIG{INT} = sub {
print "Stopping workers...\n";
kill 'TERM', @$_ for $workers;
waitpid($_, 0) for @$workers;
exit(0);
};
while (1) {
sleep 1;
}示例 2:并行任务执行
perl
#!/usr/bin/perl
use strict;
use warnings;
my @tasks = (
{ name => "Task 1", duration => 3 },
{ name => "Task 2", duration => 2 },
{ name => "Task 3", duration => 4 },
{ name => "Task 4", duration => 1 }
);
sub run_task {
my ($task) = @_;
print "Starting $task->{name}\n";
sleep $task->{duration};
print "Completed $task->{name}\n";
}
# 并行执行所有任务
my @pids;
foreach my $task (@tasks) {
my $pid = fork;
if ($pid == 0) {
run_task($task);
exit(0);
} else {
push @pids, $pid;
}
}
# 等待所有任务完成
waitpid($_, 0) for @pids;
print "All tasks completed\n";示例 3:守护进程
perl
#!/usr/bin/perl
use strict;
use warnings;
sub daemonize {
# Fork 第一次
my $pid = fork;
exit if $pid;
die "Cannot fork: $!" unless defined $pid;
# 创建新会话
setsid() or die "Cannot setsid: $!";
# Fork 第二次
$pid = fork;
exit if $pid;
die "Cannot fork: $!" unless defined $pid;
# 重定向标准输入输出
open(STDIN, '<', '/dev/null') or die "Cannot redirect STDIN: $!";
open(STDOUT, '>', '/dev/null') or die "Cannot redirect STDOUT: $!";
open(STDERR, '>&STDOUT') or die "Cannot redirect STDERR: $!";
# 信号处理
$SIG{INT} = 'IGNORE';
$SIG{TERM} = sub {
print STDERR "Daemon stopping\n";
exit(0);
};
}
# 使用
daemonize();
my $count = 0;
while (1) {
sleep 5;
$count++;
open(my $fh, '>>', 'daemon.log') or die "Cannot open log: $!";
print $fh "Heartbeat $count at " . localtime() . "\n";
close($fh);
}小结
本章节学习了 Perl 的进程管理:
- ✅ 进程创建(fork、exec、system)
- ✅ 进程通信(管道、共享内存、信号量)
- ✅ 进程控制(wait、waitpid、kill)
- ✅ 信号处理
- ✅ 实践示例
接下来,我们将学习 Perl 参考资料。