user3551911
user3551911

Reputation: 31

Perl Hash reference is changing in threads

I am using perl with threads to process socket info

ConnectionThread is responsible for receiving packets and parsing, and enque in a hash

QueueThread Is responsible for processing Queue elelemts (hash entries ) and update DB

The Hash is Events and declared as my %Events:shared;

I am passing a hash reference to the Threads, but i noticed that each thread is getting a difference hash ref value

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);

The output is as below

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)

below is the full code ( illustrative )

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;
}

Upvotes: 1

Views: 246

Answers (2)

ikegami
ikegami

Reputation: 385915

You are not directly accessing the same variable in all threads. If you did, you'd have to explicitly guarantee mutual access to the variable every time you access it (even if just to read it) to avoid crashing the program.

Each thread (including the one in which the variable is created) gets a "proxy" to the data-containing variable. The proxy is a magical variable, meaning accessing the elements of the proxy results in getters and setters being called. These getters and setters ensure the data-containing variable is never in an inconsistent state by providing mutually exclusive access to it.

$ 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)

Upvotes: 1

Sobrique
Sobrique

Reputation: 53488

Yes, this will happen. Threads do not share memory. You can sort of fake it with shared which allows you to have common variables - but you won't necessarily see the same hash memory locations.

Despite %Events being shared that's not going to print the same memory address in each thread if you print \%Events;

Given you're talking about queueing though, can I suggest instead using Thread::Queue which allows you to 'do' queue/dequeue operations in a nice easy and thread safe manner.

Upvotes: 0

Related Questions