我在Windows平台上遇到以下非常简单和小巧的Perl脚本的问题。
use strict; use warnings; use threads; use threads::shared; my $print_mut : shared; my $run_mut : shared; my $counter : shared; $counter = 30; ############################################################### sub _print($) { lock($print_mut); my $str = shift; my $id = threads->tid(); print "[Thread_$id] $str"; return; } ############################################################### sub _get_number() { lock($counter); return $counter--; } ############################################################### sub _get_cmd($) { my $i = shift; if ($^O eq 'MSWin32') { return qq{cmd /c "echo $i"}; } return "echo $i"; } ############################################################### sub thread_func() { while ((my $i = _get_number()) > 0) { my $str = 'NONE'; { lock($run_mut); my $cmd = _get_cmd($i); $str = `$cmd`; } chomp $str; _print "Got string: '$str'.n"; } return; } ############################################################### # Start all threads my @threads; for (1 .. 8) { my $thr = threads->create('thread_func'); push @threads,$thr; } # Wait for completion of the threads foreach (@threads) { $_->join; } ###############################################################
在我的Linux机器上(Perl v5.10.0),我得到正确的(预期的)结果:
$ perl〜/ tmp / thr2.pl
[Thread_1]得到了string:'30'。
[Thread_1]得到了string:'29'。
[Thread_2]得到string:'28'。
[Thread_1]得到string:'27'。
[Thread_2]得到string:'26'。
[Thread_1]得到string:'25'。
[Thread_1]得到string:'23'。
[Thread_2]得到string:'24'。
[Thread_2]得到string:'20'。
[Thread_2]得到string:'19'。
[Thread_1]得到string:'22'。
[Thread_4]得到string:'18'。
[Thread_5]得到string:'15'。
[Thread_2]得到string:'17'。
[Thread_2]得到string:'12'。
[Thread_3]得到string:'21'。
[Thread_4]得到string:'14'。
[Thread_4]得到string:'7'。
[Thread_1]得到的string:'16'。
[Thread_6]得到了string:'11'。
[Thread_2]得到string:'10'。
[Thread_2]得到string:'2'。
[Thread_3]得到string:'8'。
[Thread_5]得到string:'13'。
[Thread_8]得到的string:'6'。
[Thread_4]得到的string:'5'。
[Thread_1]得到了string:'4'。
[Thread_6]得到的string:'3'。
[Thread_7]得到string:'9'。
[Thread_2]得到string:'1'。
$
但是,在Windows(Perl v5.10.1)中,我弄得一团糟:
C:> perl Z: tmp thr2.pl
[Thread_1]得到了string:'30'。
[Thread_2]得到string:'29'。
[Thread_2]得到string:'21'。
[Thread_6]得到string:'26'。
[Thread_5]得到string:'25'。
[Thread_5]得到了string:'17'。
[Thread_8]得到string:'23'。
[Thread_1]得到string:'22'。
[Thread_1]得到的string:'14'。
[Thread_2]得到string:'20'。
[Thread_6]得到了string:'18'。
[Thread_7]得到string:'24'。
[Thread_7]得到string:'9'。
[Thread_8]得到string:'15'。
[Thread_3]得到string:'28'。
[Thread_3]得到的string:'6'。
[Thread_4]得到了string:'12'。
[Thread_2]得到的string:'[Thread_4]得到的string:'27'。
19' 。
[Thread_6]得到string:'10'。
[Thread_5]得到的string:'16'。
[Thread_7]得到string:'8'。
[Thread_8]得到了string:'7'。
[Thread_1]得到了string:'13'。
[Thread_3]得到了string:'5'。
[Thread_4]得到的string:'4'。
[Thread_2]得到string:'11'。
[Thread_6]得到的string:'[Thread_2]得到的string:'3'。
[Thread_5]得到了string:'2'。
1。
C:>
当我通过反引号从线程函数运行一个命令(无关紧要的命令)来收集它的输出时,问题就发生了。
为什么在反引号中出现语法错误,尽pipe它在terminal工作?
如何在perl中加载STDIN以反引号(无需写入临时文件)
我在Perl中的线程和在Windows上的Perl方面的经验非常有限。 我总是尽量避免在Perl中使用线程,但是这次我必须使用它们。
我没有设法在perldoc和Google中find答案。 有人能解释我的脚本有什么问题吗?
提前致谢!
我可以在我的WinXP上重新创建这个问题,结果相同。 但是,这似乎只影响STDOUT。
如果我打印到一个文件,问题不会出现,也不会出现在我使用STDERR的时候,就像德米特里所建议的那样。 但是,如果我写入STDOUT和一个文件,它会出现。 这是一个线索。
在打印中添加另一个反引号变量会导致问题出现在两个地方,每个连接之前。
在测试时,我决定chomp()是不够的,所以我补充说
$str =~ s/[^w]+//g;
有了这个有趣的结果:
[Thread_6] Got string: 'Thread_4Gotstring1925'.
这似乎意味着$str实际上保存了另一个线程的整个打印缓冲区。 至少可以说,这很奇怪。
除非这个…
两个线程在同一时间运行:
print "[Thread_4] Got string: '19'.n" $str = `echo 25`
打印和回应可能共享相同的STDOUT缓冲区,所以它们都进入$str ,结果打印:
chomp "[Thread_4] Got string: '19'.n25n" print "[Thread_6] Got string: [Thread_4] Got string: ''19'n25'.n"
总之,一个Windows的问题。 如果您想“解决”问题,请确保回显和打印都被锁定的值覆盖。 将thread_func移动到thread_func下面的_print应该提供一个干净的打印。 即:
{ lock($run_mut); my $cmd = _get_cmd($i); $str = `$cmd`; chomp $str; _print "Got string: '$str'.n"; }
一个有趣的方法来验证这将是用一些写入STDERR的Windows命令替换回声,并看看是否与perl中打印到STDERR的打印冲突。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。