“线程安全”问题的一般解决方法是“要求”和“导入”。这些必须在发生任何类型的线程实例化之后调用,并且之后不能创建线程(从加载模块的任何位置 - 在“主”中都可以)。
所以 - 因为你没有给我们任何代码,我已经使用了模块之外的示例。您需要进行相应的修改。
#!/usr/bin/env perl
use strict;
use warnings;
use threads;
use Thread::Queue;
my $num_workers = 10;
my %generalargs = (
'access' => 'ssh',
'server' => 'netconf',
'command' => 'junoscript netconf',
'debug_level' => 1,
'client_capabilities' => [
'urn:ietf:params:xml:ns:netconf:base:1.0',
'urn:ietf:params:xml:ns:netconf:capability:candidate:1.0',
'urn:ietf:params:xml:ns:netconf:capability:confirmed-commit:1.0',
'urn:ietf:params:xml:ns:netconf:capability:validate:1.0',
'urn:ietf:params:xml:ns:netconf:capability:url:1.0?protocol=http,ftp,file',
'http://xml.juniper.net/netconf/junos/1.0',
]
);
my @host_list = (
{ 'hostname' => 'routername',
'login' => 'loginname',
'password' => 'secret',
},
{ 'hostname' => 'routername2',
'login' => 'differentname',
'password' => 'anotherpassword',
},
);
my $work_q = Thread::Queue->new;
sub some_helper_sub_that_isnt_a_thread {
my ( $input, $process ) = @_;
return "$input";
}
sub do_netconf_stuff {
require 'Net::NetConf::Manager';
Net::NetConf::Manager->import;
while ( my $item = work_q->dequeue ) {
my $device = Net::NetConf::Manager->new( %{$item} );
print 'Could not create Netconf device' unless $device;
some_helper_sub($device);
}
}
threads->create( \&do_netconf_stuff ) for 1 .. $num_workers;
foreach my $host (@host_list) {
$work_q->enqueue( { %$host, %generalargs } );
}
$work_q->end;
$_->join for threads->list;
这里发生的是每个线程独立 - 在运行时 - 导入Net::NetConf::Manager
并且这意味着它们每个都被单独实例化。然后,您可以从线程内调用其他子程序,它们会正常工作 - 您已加载到该线程的全局命名空间中。
然后你不能做的事情是启动额外的线程来“继承”那个导入的环境。
注意 - 这不是 100% 肯定会工作 - 线程可能会发生冲突还有其他原因(例如尝试侦听相同的端口号、锁定相同的文件等)。但是由于共享文件句柄等,您将避免模块内的问题。