Perl线程安全模块

9

我想将自己编写的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

我收到的输出如下:
你好线程编号:1
分段错误
这是否意味着该模块不是线程安全的,还是另一个问题?
谢谢。

1
尝试编写最小的程序,以引起分段错误。 - mob
1个回答

32

一般来说,核心模块和高可见度模块都是线程安全的,除非它们的文档另有说明。

话虽如此,你的文章中有一些错误:

  1. share($CSV)
    这会清除 $CSV(一个 blessed hashref),正如在 threads 文档中所述。通常情况下,你要在初始化之前分享复杂对象,或者在这种情况下分享一些简单的 $lock 变量。
    由于 $CSV 保存了底层 XS 的状态,这可能导致未定义的行为。

    但这并不是你的段错误。

  2. threads->create(\&sayHello('1'));
    你错误地在主线程中调用了 sayHello(1) 并将其返回值的引用作为(无效的)起始例程传递给 threads->create()。 你应该这样写:

    threads->create(\&sayHello, '1');
    

    但这不是你的段错误。

    (编辑 仅为澄清--在此处存在一个错误的起始例程并不会在任何情况下导致SEGV。如果传递了无法识别的子程序名称或非-CODE引用,则threads::create会正确地发出投诉。然而,在你的情况下,你的段错误太快了,以至于无法到达此错误处理程序。)

  3. 编码不是线程安全的。
    再次encodings所述encoding模块不是线程安全的。 以下是我能够找到的最小代码,以重现你的症状:

  4. use threads;
    open my $OUTPUT , ">:encoding(utf8)", "/dev/null" or die $!;
    threads->create( sub {} )->join;
    

    如果你感兴趣的话,那么这就是在i686-linux-thread-multi上使用threads-1.77的perl 5.12.1。删除“utf8”魔法,它就可以正常工作了。

    这就是你的段错误。


这让我省去了数小时寻找段错误原因的时间。谢谢! - Ventzi Zhechev

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接