连接线程时出现Perl段错误 [英] Perl seg fault while joining threads

查看:143
本文介绍了连接线程时出现Perl段错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个类似于以下的代码.我有一个主要脚本正在调用另一个名为initial.pm的模块. initial.pm打开与AMQP服务器(在我的情况下为RabbitMQ)的连接,并使用Net :: AMQP :: RabbitMQ库建立连接.一切正常,但当我尝试加入线程时出现分段错误.

I have a code similar to the below. I have one main script which is calling another module named initial.pm. initial.pm opens up connection with an AMQP server (In my case RabbitMQ)and using Net::AMQP::RabbitMQ library for establishing the connection. Everything works fine except when I try to join my threads I get segmentation fault.

我认为Net :: AMQP :: RabbitMQ不是线程安全的.但这仅由主线程使用.我非常确定,如果您仅复制并粘贴以下代码,便可以重现该错误.

I think the Net::AMQP::RabbitMQ is not thread safe. But this is only being used by the main thread. Im pretty sure you can reproduce the error if you just copy and past the codes below.

我该如何解决?

main.pl

#!/usr/bin/perl
use Cwd qw/realpath/;
use File::Basename qw/dirname/;
use lib 'lib';
use threads;
use threads::shared;
use initial;

my @threads = ();
my $run :shared = 1;

my $init = load initial($name);

$SIG{'TERM'} = sub {
    $run = 0;
};

threads->create(\&proc1);
threads->create(\&proc2);


while($run){
    sleep(1);
    print "I am main thread\n";
}

$_->join() for threads->list();

sub proc1 {
    while($run){
        sleep(1);
        print "I am child thread 1 \n"
    }
}

sub proc2 {
    while($run){
       sleep(1);
       print "I am child thread 2 \n";
    }
}

lib/initial.pm

package initial;

use Net::AMQP::RabbitMQ;
use Cwd qw/realpath/;
use File::Basename qw/dirname/;

my $mq;
my $stop = 0;

sub load {
    my $class = shift;
    my $self = {};
    connectq();
    bless $self,$class;
    return $self;
}

sub connectq {
    $mq = Net::AMQP::RabbitMQ->new();
    my ($host,$port,$user,$pass) = ('localhost','5672','guest','guest');
    $mq->connect($host, {
        user => $user,
        password => $pass,
        port => $port,
        timeout => 10,
    });

    $mq->channel_open(1);
    $mq->consume(1, 'logger');
}

1;

推荐答案

我无法直接重现您的问题,因为我没有安装该库.

I can't reproduce your problem directly, because I don't have the library installed.

在非线程安全的模块中伪造"线程安全性的一种方法是将使用"范围限制为仅使用它的位置.

One way of 'faking' thread safety in a not-thread-safe module is to rescope your 'use' to only the bit where you'll be using it.

您看到,启动线程时,它将复制程序状态-加载的库和所有内容.

You see, when you start a thread, it copies the program state - loaded libraries and everything.

如果您跑步(类似):

#!/usr/bin/env perl

use strict;
use warnings;

use XML::Twig;
use Data::Dumper;

sub thread1 {
    print threads->self->tid.": Includes:", Dumper \%INC,"\n";
}


#main;

print "Main includes:", Dumper \%INC,"\n";
threads -> create ( \&thread1 );

您会看到两者都加载了XML::Twig.如果模块的加载"过程导致了一些状态更改(并且可以),那么您将立即面临潜在的线程安全问题.

You'll see XML::Twig is loaded in both. If the process of 'loading' the module causes some state changes (and it can) then you immediately have a potential thread-safety issue.

但是,如果您这样做:

#!/usr/bin/env perl

use strict;
use warnings;

use threads;
use Data::Dumper;

sub thread1 {
    require XML::Twig;
    XML::Twig -> import;
    print threads->self->tid.": Includes:", Dumper (\%INC),"\n";
}


#main;

print "Main includes:", Dumper (\%INC),"\n";
threads -> create ( \&thread1 );
foreach my $thr ( threads -> list ) { 
   $thr -> join;
}

有效地使模块动态加载到线程中-模块仅存在于一个代码实例"中,因此您不太可能被线程安全"问题绊倒.

You effectively cause the module to be dynamically loaded within the thread - the module is only present in one 'code instance' so you are much less likely to be tripped up by 'thread safety' issues.

或者-用fork ing代替thread ing ...也可以.这有稍微不同的安全性"问题.

Alternatively - forking instead of threading ... might be an alternative. This has slightly different 'safety' problems.

但是确实没有办法避免这种情况.即使使用共享变量,核心问题是-当您进行线程处理时,代码的位点以不同的顺序发生.结果可能会发生各种各样的水果事件.共享var是确保每次检查 same 变量的一种方法-例如共享$init,但这可能会使情况变得更糟,因为您然后可能会踩踏具有不同线程的同一实例/套接字.

But there really is no way to avoid this. Even with shared variables, the core problem is - when you thread, bits of code happen in a different order. There's all sorts of fruity things that can happen as a result. A shared var is one way of ensuring it's the same variable being checked each time - e.g. share $init, but that may well make things worse, because you're then potentially trampling over the same instance/sockets with different threads.

但是,您可以将线程安全性"问题减少到有限的范围,并使用例如Thread::Queue将消息传递到模块用户"线程或从模块用户"线程传递消息.

You can, however, reduce the 'thread safety' problem to a limited scope, and use e.g. Thread::Queue to pass messages to/from your 'module user' thread.

这篇关于连接线程时出现Perl段错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆