gpt4 book ai didi

multithreading - 加入线程时出现 Perl 段错误

转载 作者:行者123 更新时间:2023-12-03 13:04:36 27 4
gpt4 key购买 nike

我有一个类似于下面的代码。我有一个主脚本正在调用另一个名为 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;

最佳答案

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

在非线程安全模块中“伪造”线程安全的一种方法是将您的“使用”范围重新调整到您将使用它的位置。

您会看到,当您启动一个线程时,它会复制程序状态 - 加载的库和所有内容。

如果您的运行(类似):

#!/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 ing 而不是 thread ing ...可能是另一种选择。这有稍微不同的“安全”问题。

但是真的没有办法避免这种情况。即使使用共享变量,核心问题是 - 当你线程时,代码位以不同的顺序发生。结果可能会发生各种果味的事情。共享变量是确保每次检查相同变量的一种方法 - 例如分享 $init ,但这很可能会让事情变得更糟,因为你可能会用不同的线程践踏相同的实例/套接字。

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

关于multithreading - 加入线程时出现 Perl 段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31279157/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com