我正在尝试适应在Windows上运行的Perl代码,需要启动一个单独的进程并执行一些多线程流程(该进程可能会在多个时间点继续运行或退出 - 正在执行线程流)。
基本上,逻辑是这样的:
use Win32::Process;
use threads;
use strict;
my $proc;
Win32::Process::Create($proc,'dir','',0,NORMAL_PRIORITY_CLASS(),".");
my $t1= threads->create(\&thread_proc);
my $t2= threads->create(\&thread_proc);
sleep 2;
print "Waiting for thread ".$t1->tid." to exit\n";
$t1->join();
print "Waiting for thread ".$t2->tid." to exit\n";
$t2->join();
print "All done.\n";
# Cleanup would be here
sub thread_proc {
foreach (1..5) {
print "Thread ".threads->tid." waiting $_\n";
sleep 1;
}
return 0;
}
当执行到达第二个join
时,Perl中止(调试器声称堆已损坏)。
如果我在上面发表评论Win32::Process::Create
,那就行了。
用Win32::Process
替换Win32::Job
没有用,虽然它还会产生消息
Free to wrong pool 4a47c0 not 328400 at ...
将整个线程逻辑包装到BEGIN {}
块似乎会使崩溃消失,但这不是一个理想的解决方法,因为在实际代码中,线程相关的逻辑更复杂,不可能容易本地化。
在Win32::Process或Win32::Job文档(或其他任何地方)中,我找不到有关这些模块的线程不安全的任何信息。
所以,问题是,代码是错误还是模块的一般问题,在后一种情况下,是否有任何类似的已知合理的防撞安全?
草莓perl 5,版本24,颠覆1(v5.24.1)内置 MSWin32-x64的多线程
答案 0 :(得分:2)
目前尚不清楚你要做什么。您是否打算将这个过程产生到比Perl程序更长的时间?你打算与你产生的过程沟通吗?
在大多数情况下,除非您想以Windows特定方式与fork
进行交互,否则仅使用普通$proc
(在Windows上模拟,但大多数工作都会更好)将会更好。另外,请注意,dir
内置cmd.exe
内容Win32::Process
因此dir.exe
将无法在其中运行,除非您有dir.com
或dir.bat
或您%PATH%
上的#!/usr/bin/env perl
$| = 1;
use v5.24; # why not?
use strict;
use warnings;
use threads;
use feature 'signatures';
no warnings 'experimental::signatures';
use autouse Carp => qw( croak );
use Win32::GuiTest qw( FindWindowLike SendKeys SetForegroundWindow );
use Win32::Process;
use Win32;
run();
sub run {
Win32::Process::Create(
my $proc,
'C:\WINDOWS\system32\notepad.exe',
'notepad.exe',
0,
+NORMAL_PRIORITY_CLASS,
'.',
) or croak Win32::FormatMessage(Win32::GetLastError());
my @thr = map threads->create(\&task), 1 .. 2;
threads->yield;
my @windows;
do {
@windows = FindWindowLike(0, 'Notepad');
} until (@windows);
wait_for_thread($_, $windows[0]) for @thr;
say 'All done.';
SetForegroundWindow($windows[0]);
SendKeys('%fxn');
$proc->Wait(+INFINITE);
return;
}
sub task {
my $tid = threads->tid;
say "Thread $tid waiting ($_)" for 1 .. 5;
threads->yield;
return;
}
sub wait_for_thread($thr, $window) {
my $msg = sprintf "Waiting for thread %d\n", $thr->tid;
print $msg;
SetForegroundWindow($window);
SendKeys($msg);
$thr->join;
return;
}
或类似内容。
我可以使用以下程序复制崩溃:
threads
我在调试器中得到了这个:
Win32::Process
和#!/usr/bin/env perl
$| = 1;
use v5.24; # why not?
use strict;
use warnings;
use threads;
use feature 'signatures';
no warnings 'experimental::signatures';
use autouse Carp => qw( croak );
use Win32::GuiTest qw( FindWindowLike SendKeys SetForegroundWindow );
run();
sub run {
defined(my $cpid = fork)
or croak "Failed to fork: $!";
if (!$cpid) {
system 'notepad';
exit;
}
my @thr = map threads->create(\&task), 1 .. 2;
threads->yield;
my @windows;
do {
@windows = FindWindowLike(0, 'Notepad');
} until (@windows);
wait_for_thread($_, $windows[0]) for @thr;
say 'All done.';
SetForegroundWindow($windows[0]);
SendKeys('%fxn');
1 while waitpid(-1, 0) > 0;
return;
}
sub task {
my $tid = threads->tid;
say "Thread $tid waiting ($_)" for 1 .. 5;
threads->yield;
return;
}
sub wait_for_thread($thr, $window) {
my $msg = sprintf "Waiting for thread %d\n", $thr->tid;
print $msg;
SetForegroundWindow($window);
SendKeys($msg);
$thr->join;
return;
}
之间的互动可能会暴露出错误*。
另一方面,以下版本似乎工作正常:
Win32::Process
正如我所提到的,除非有特定原因要使用fork
,否则最好使用 <div class="form-group">
<input type="submit" class="btn-btn-success" value="Add Contact">
</div>
。
*请随时查看P5P。