我正在尝试使用我编写的Perl程序并对其进行处理。问题是我读到一些模块不是“线程安全的”。我如何知道模块是否是线程安全的?我环顾四周找不到一个清单。
要测试我经常使用的一个模块(Text :: CSV_XS),我尝试了以下代码:
use strict;
use warnings;
use threads;
use threads::shared;
require Text::CSV_XS;
my $CSV = Text::CSV_XS->new ({ binary => 1, eol => "\n" }) or die("Cannot use CSV: ".Text::CSV->error_diag());
open my $OUTPUT , ">:encoding(utf8)", "test.csv" or die("test.csv: $!");
share($CSV);
my $thr1 = threads->create(\&sayHello('1'));
my $thr2 = threads->create(\&sayHello('2'));
my $thr3 = threads->create(\&sayHello('3'));
sub sayHello
{
my($num) = @_;
print("Hello thread number: $num\n");
my @row = ($num);
lock($CSV);{
$CSV->print($OUTPUT, \@row);
$OUTPUT->autoflush(1);
}#lock
}#sayHello
我收到的输出如下:
Hello thread number: 1 Segmentation fault
这是否意味着模块不是线程安全的,还是另一个问题?
由于
答案 0 :(得分:32)
一般来说,除非他们的文档另有说明,否则核心和高可见性模块 是线程安全的。
也就是说,你的帖子中有一些失误:
share($CSV)
这会清除$CSV
(祝福的hashref),just as documented in threads
。通常,您希望将()之前的复制对象初始化,或者在这种情况下,在线程之间共享()一些哑的$lock
变量。
由于$CSV
保持基础XS的状态,因此可能导致未定义的行为。
但这不是你的段错误。
threads->create(\&sayHello('1'));
您错误地在主线程中调用sayHello(1)
并将对其返回值的引用传递给threads->create()
作为(伪造)启动例程。
你想说:
threads->create(\&sayHello, '1');
但这不是你的段错误。
(编辑只是为了澄清 - 这里的错误启动例程在任何情况下都不会冒SEGV的风险。threads::create
如果无法识别的子例程名称或非CODE引用是正确的抱怨但是,在你的情况下,你很快就会陷入错误处理。)
编码不是线程安全的
再次as documented in encodings
,encoding
模块不是线程安全的。
这是我可以用来重现症状的最小代码:
use threads;
open my $OUTPUT , ">:encoding(utf8)", "/dev/null" or die $!;
threads->create( sub {} )->join;
如果您感兴趣的话,那就是i686-linux-thread-multi上的线程为1.77的perl 5.12.1。放弃“utf8”魔法,它的效果很好。
这是你的段错误