Perl Hash引用正在改变线程

时间:2015-04-12 11:30:21

标签: multithreading perl hash hashref

我正在使用perl和线程来处理套接字信息

ConnectionThread 负责接收数据包和解析,并在哈希中加入

QueueThread 负责处理Queue elelemts(哈希条目)和更新DB

哈希是事件,并声明为我的%事件:共享;

我正在向线程传递哈希引用,但我注意到每个线程都获得了差异哈希引用值

my $hash_ref1 = \%Events ; # referencing
print "Hash ref in main is 1 " . $hash_ref1 ."\n";
my $thr1 = threads->create(\&ConnectionThread, $hash_ref1 );
my $thr2 = threads->create(\&QueueThread, $hash_ref1);

输出如下

Hash ref in main is 1 HASH(0x825faa4)
Hash ref is ConnectionThread is HASH(0x8493544)
Thread started ..
Hash ref is Queue thread is HASH(0x852dd9c)

下面是完整代码(说明性)

use strict;
use warnings;
use Socket;
use threads;
use threads::shared;
use DBI;
my %Events:shared;

sub checkSize {
    my $size;
    $size =keys %Events;
    print "Size of Queue in Check is ***" .$size ." \n";
}

sub QueueThread {
    my ($hash_ref) = @_;
    print "Hash ref is Queue thread is " . $hash_ref ." \n";
    while (1==1) {
        sleep (5);
    }
}

sub ConnectionThread {
    my ( $hash_ref ) = @_;
    print "Hash ref is ConnectionThread is " . $hash_ref ." \n";
    while (1==1) {
        sleep(5);
    }
}

my $hash_ref1 = \%Events;
print "Hash ref in main is 1 " . $hash_ref1 ."\n";
my $thr1 = threads->create(\&ConnectionThread, $hash_ref1 );
my $thr2 = threads->create(\&QueueThread, $hash_ref1);
print "Thread started ..\n";
while (1==1) {
    sleep 10;
}

2 个答案:

答案 0 :(得分:1)

您不是在所有线程中直接访问同一个变量。如果你这样做了,那么你每次访问变量时都必须明确保证对变量的相互访问(即使只是为了阅读它),以避免程序崩溃。

每个线程(包括创建变量的线程)获得一个 "代理"到包含数据的变量。代理是一个神奇的变量,意味着访问代理的元素会导致调用getter和setter。这些getter和setter通过提供对它的互斥访问来确保包含数据的变量永远不会处于不一致状态。

$ perl -Mthreads -Mthreads::shared -MDevel::Peek \
   -E'my %h :shared; ( async { Dump(%h); } )->join; Dump(%h);' 2>&1 |
      grep -P '^\S|^ {8}IV'
SV = PVHV(0x1ed5f90) at 0x1f6fd68   <-----+
        IV = 31930352               <--+  |
SV = PVHV(0x1d70af0) at 0x1d880d0   <--|--+------ Two different vars
        IV = 31930352               <--+--------- Proxying the same var (0x1e737f0)

答案 1 :(得分:0)

是的,这会发生。线程不共享内存。您可以使用shared对其进行伪造,以允许您拥有常见变量 - 但您不一定会看到相同的散列内存位置。

尽管%Eventsshared print \%Events;如果Thread::Queue

,我们不会在每个帖子中打印相同的内存地址

鉴于您正在谈论排队,我是否可以建议您使用{{1}},这样您就可以“排序”。以简单易用且线程安全的方式排队/出列操作。