在一个Perl模块中使用Win32进程和线程

时间:2018-02-16 18:02:37

标签: multithreading perl thread-safety

我正在尝试适应在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::ProcessWin32::Job文档(或其他任何地方)中,我找不到有关这些模块的线程不安全的任何信息。

所以,问题是,代码是错误还是模块的一般问题,在后一种情况下,是否有任何类似的已知合理的防撞安全?

  

草莓perl 5,版本24,颠覆1(v5.24.1)内置   MSWin32-x64的多线程

1 个答案:

答案 0 :(得分:2)

目前尚不清楚你要做什么。您是否打算将这个过程产生到比Perl程序更长的时间?你打算与你产生的过程沟通吗?

在大多数情况下,除非您想以Windows特定方式与fork进行交互,否则仅使用普通$proc(在Windows上模拟,但大多数工作都会更好)将会更好。另外,请注意,dir内置cmd.exe内容Win32::Process因此dir.exe将无法在其中运行,除非您有dir.comdir.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

我在调试器中得到了这个:

Visual Studio Debugger

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