我有类似下面的代码。我有一个主脚本调用另一个名为initial.pm的模块。 initial.pm打开与AMQP服务器(在我的案例中为RabbitMQ)的连接,并使用Net :: AMQP :: RabbitMQ库建立连接。一切正常,除非我尝试加入我的线程,我得到分段错误。
我认为Net :: AMQP :: RabbitMQ不是线程安全的。但这只是主线程使用。我很确定如果您只是复制并通过以下代码,您可以重现错误。
我该如何解决?
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;
答案 0 :(得分:1)
我无法直接重现您的问题,因为我没有安装库。
在非线程安全模块中“伪造”线程安全性的一种方法是将“使用”重新调整到您将使用它的位。
你看,当你启动一个线程时,它会复制程序状态加载的库和所有东西。
如果你的跑步(类似的话):
#!/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
都加载了#!/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;
}
。如果“加载”模块的过程导致某些状态更改(并且可以),那么您立即遇到潜在的线程安全问题。
但是,如果您改为:
fork
你有效地导致模块在线程中动态加载 - 模块只出现在一个'代码实例'中,因此你不太可能被'线程安全'问题绊倒。
或者 - thread
而不是$init
......可能是另一种选择。这有“略微不同”的“安全”问题。
但实在没有办法避免这种情况。即使使用共享变量,核心问题是 - 当您进行线程处理时,代码位会以不同的顺序发生。结果可能会发生各种各样的果味。共享var是确保每次检查相同变量的一种方法 - 例如分享Thread::Queue
,但这可能会使事情变得更糟,因为你可能会使用不同的线程践踏相同的实例/套接字。