gpt4 book ai didi

linux - 使用 perl 的过程控制和并发程序

转载 作者:太空狗 更新时间:2023-10-29 11:13:58 27 4
gpt4 key购买 nike

我需要什么: 我的 perl 程序生成了一些外部程序。然后它将监视外部程序并在它们因任何原因失败时重新启动它们。 perl 程序无法等待它启动的进程。我不关心衍生程序的 STDOUT 或 STDERR,并且想完全关闭它们的任何输出

我目前遇到的问题:首先,除了流程抽象和流程管理的基础知识之外,我不太了解。我的 perl 程序及其子程序进程终止的不同场景将导致“zombies”(曾经是我的 perl 程序子程序的程序将被 init 采用)

使用open创建外部子程序

# please note I have simplified the shell commands for this example
$SIG{CHLD}='IGNORE';
open(my $ph, "-|", "./sc_serv --options") or die $!;
open(my $ph, "-|", "(ffmpeg --opt1 --opt2) | vlc --many-options --etc") or die $!;

如果您查看下面 pstree -p 6947 的输出,您可以看到我的 perl 程序创建了两个子进程 sc_serv(6948)sh( 6949)sh(6949) <- 创建这个 shell 是因为 ffmpeg(6950) 被传送到 vlc(6952)(至少我相信这是为什么需要一个 shell ,我不是 100% 确定。)

perl(6947)─┬─sc_serv(6948)─┬─{sc_serv}(6964)
│ ├─{sc_serv}(6965)
│ └─{sc_serv}(6966)
└─sh(6949)─┬─ffmpeg(6950)
└─vlc(6952)─┬─{vlc}(6980)
├─{vlc}(6983)
└─{vlc}(6985)

现在如果我杀掉 perl(6947) 整个家谱将被正确终止和清理,虽然杀掉 sh(6949) 会留下它的 child 来初始化创建有点乱。

请注意,如果我没有将 $SIG{CHLD} 设置为 IGNORE,杀死 sh(6949) 将留下它的 child init 并且还将使 sh(6949) 成为一个 defunct 进程。我不明白这是为什么。所以,

问题一。 为什么在这种情况下我必须将 $SIG{CHLD} 设置为 IGNORE

问题 2。 我如何确保如果我需要杀死 sh(6949) 它的所有子级也会被杀死?

#

我还尝试过将 forksystemexec 一起使用。 fork 的结果与使用 open 的结果非常相似。这是我试过的使用 system 的子程序。

sub start_vlc {

my $pid = fork();
if( $pid == 0 ) {
close STDOUT;
close STDERR;
system "(ffmpeg --opt1 --opt2) | vlc --many-options --etc";
}
else {
return $pid;
}

}

使用这个子程序会遇到与上面几乎相同的问题,但现在子程序是克隆的 perl 程序。杀死 perl(25991) 会让它的所有 child 都去初始化,造成和上面一样的困惑。同时杀死所有进程的父进程 perl(25982) 也不会正确地杀死它的所有子进程。它会杀死一些但不是全部,造成比我尝试打开更多的困惑。

perl(25982)─┬─perl(25989)───sc_serv(25990)─┬─{sc_serv}(25992)
│ ├─{sc_serv}(25993)
│ └─{sc_serv}(25994)
└─perl(25991)───sh(25995)─┬─ffmpeg(25996)
└─vlc(25997)─┬─{vlc}(26042)
├─{vlc}(26044)
└─{vlc}(26046)

问题 3。 我如何将 forksystemexec 一起使用来生成外部程序并控制它们的终止而不留下孤儿来初始化?

请尽可能详细,我不反对尝试模块,但我宁愿学习如何在没有它们的情况下执行此操作,以更好地理解使用 perl 进行过程控制。

引用文献:

run process in background without being adopted by init, Perl

How can i get process id of UNIX command i am triggering in a Perl script?

最佳答案

问题 1. 为什么在这种情况下我必须将 $SIG{CHLD} 设置为 IGNORE?

当您设置它时,它会告诉您的子进程不要逗留,以免被您的父进程使用 waitwaitpid 收割。这意味着没有僵尸。重要的是 - 当您 fork() 时,它也会级联到子级。所以你的 sh 进程继承了它。

当设置为 IGNORE 时,您的 sh 将在被杀死时立即退出,并且子级将重新设置为 init。如果你不设置它,那么 sh 将保持僵尸状态,等待父级使用 wait() 收割它并收集返回码。你可能想要这个,因为你的 parent 可以检测退出条件,并做任何需要的清理。

问题 2。如果我需要杀死 sh(6949),我如何确保它的所有子级也将被杀死?

或者:杀死一个负进程 id,这将向整个树发送相同的信号。或者:使用信号处理程序并捕获信号 - 如 SIGHUPSIGUSR1 - 然后使用该处理程序将信号传播到适当的子进程。可能是两者的结合。 (参见:Best way to kill all child processes)

问题 3. 如何将 fork 与 system 或 exec 一起使用来生成外部程序并控制它们的终止而不留下孤儿来初始化?

你想避免什么?一个进程所做的所有“重设”意味着 init 将在它们退出并自动进入僵尸状态时清理它们。 (您可以通过设置 $SIG{'CHLD'} 来避免)

正如有人在评论中提到的那样 - 可能值得查看 threads 而不是 fork。它是一种不同的 IPC 模型——它可能效率较低,但使某些类型的编程更容易和更清晰——特别是任何使用共享内存类型操作模型的编程。

关于linux - 使用 perl 的过程控制和并发程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25917089/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com