Windows中真正有用的进程分离

问题描述 投票:2回答:2

我正在尝试编写一个以不同间隔运行命令行的分发程序。想想cron,在这里。理想情况下,这将是跨平台的,但cron已存在于* nix中,因此这主要适用于Windows。

鉴于尝试生成并保持类似守护进程的perl脚本运行稳健的许多问题,我的想法是让操作系统的调度程序每分钟启动脚本并让脚本确定要运行哪些命令行然后执行此操作。你们中的一些人已经可以看到问题......

如果Windows Scheduler已在运行,则它将不会运行该作业。因此,要运行cron-ish perl脚本,必须在不到一分钟的时间内完成,否则可能会跳过一些预定的命令行。例如,每小时运行一次超过一分钟的事情会使运行时间超过一小时的运行1分钟。例如,尝试运行此命令的perl程序:

system 1,'perl -e "sleep 10"';

您认为程序将立即返回到命令提示符,并在Windows的后台运行“sleep 10”...但是不行,父脚本在退出前等待10秒。

我目前的解决方案是实际循环程序,直到所有命令完成...并且每分钟,重新进入读取类似crontab的输入的循环。出于各种原因,这是一场噩梦,其中最重要的原因是我的调度程序脚本变得对它启动的命令感到满意。

有人可能会认为分支系统调用以运行每个命令都可以,但在Windows中,父脚本在子项完成之前不会退出。由于一些奇怪的原因,即使命令行使用Windows'start'命令,情况仍然如此。

我尝试过Win32 :: Process但是它有一些奇怪的限制,主要是它需要一个明确的Windows程序来识别。我在Win32 :: Process周围编写了一个包装器,它在命令行中运行程序,在路径中找到它(也通过使用$ ENV {PATHEXT}查找程序类型...例如,Win32 ::进程不接受'记事本'所以我必须确定'notepad.exe'是它想要的,然后在路径中找到它。如果找不到程序,我假设程序是$ ENV {COMSPEC}并添加'/ c'。所有这些都很有效......直到......

如果我使用这种方法,每当计划中出现一些命令时,Windows就会在我的屏幕上弹出。如果您正在键入电子邮件并且窗口焦点反弹,那么您可能会非常痛苦,因此您突然在其他窗口中键入内容。生产力杀手!

输入开始。使用START / MIN将最小化新进程,因此它们不会弹出我正在做的任何事情。但START不是一个真正的程序,所以试图为我的Win32 :: Process包装器找到它然后默认为$ ENV {COMSPEC}。一切都很好......所以像“dosomething.pl arg1 arg2”这样的命令可以重新调整为“cmd / c start / MIN dosomething.pl arg1 arg2”。哪个效果很好...直到......

...我尝试像“domsomething.pl arg1 arg2> out.txt”这样的命令。将其更改为“cmd / c start / MIN dosomething.pl arg1 arg2> out.txt”将start的输出发送到out.txt ...这通常没什么(开始是相当安静的那种方式)。

另外,我的Win32 :: Process包装器不够精明(如果我避开cmd并启动东西)知道诸如“dosomething.pl arg1 arg2”之类的命令需要是“perl -S dosomething.pl arg1 arg2” ...然后perl可以在路径中找到perl.exe。它是识别.pl扩展并运行perl的Windows。 Win32 :: Process不会向Windows询问此类信息,具体取决于我自己解决的问题。我想在某个地方有一个Win32模块可以为我解决这个问题。谁知道这是真的吗?

所以,我在这里。没有100%分离进程的好方法... fork()和“system 1,$ cmd”都保持父进程运行直到子进程完成。 Win32 :: Process是一个噩梦,可以自动尝试并收集正常工作所需的一切。

有人剥过这只猫吗?有什么建议?谢谢吨,你们呀。

perl
2个回答
1
投票

自从我给这只猫剥皮以来已经有一段时间了,但是我的笔记说工作流程是这样的

use Win32::Process;
@cmd = (...);    # I think it's ok to begin with START or CMD
my $procObj;
Win32::Process::Create( $procObj, $cmd[0], join(' ',@cmd), 0,
                        &Win32::Process::DETACHED_PROCESS, "/" )
    or die "failed to create detached proc: ",
           Win32::FormatMessage( Win32::GetLastError() );

如果你的命令有空格或其他元字符,那join(' ',@cmd)就是一个陷阱,所以让我们说这个问题超出了这个答案的范围。


0
投票

这就是我所处的位置......有没有人有更好的主意?

因此,我想要运行的命令是$ cmdline,代码变为:

my $pgm=$ENV{COMSPEC};
$cmdline='/c start /min cmd /c '.$cmdline;
my $flags=DETACHED_PROCESS;
Win32::Process::Create(my $ProcessObj,
    $pgm,
    $cmdline,
    0, # setting this to 1 will make this script wait on this process to end
    $flags,
    '.', # working dir
);

然后,如果我想从命令中捕获输出,我必须“逃避”'>'和'&'字符:

$cmdline='pl2 E:\\scripts\\PERLDO_Stuff\\Sums2.perldo ^>e:\\pl2.log 2^>^&1'

(注意:pl2.pl是我的PATH中的perl脚本)

注意>file.ext现在如何^>file.ext2>&1变成2^>^&1。到目前为止,这是我实现这一目标的唯一方法。

有没有人对此有任何其他想法?

© www.soinside.com 2019 - 2024. All rights reserved.