[Perl]: Not a CODE reference ... my 1st script - multithreading

i am getting the following error when i am trying to run my 1st Perl script:
[id=0 # 0] : IP address "3.3.3.3" corresponds to device "core".
Thread 1 terminated abnormally: Not a CODE reference at ./dev_ithread.pl line 23.
[id=0 # 1] : IP address "5.5.5.5" corresponds to device "border".
Thread 2 terminated abnormally: Not a CODE reference at ./dev_ithread.pl line 23.
and here is what i have written so far
#!/usr/bin/perl
use strict ;
use warnings ;
use diagnostics ;
use threads ;
use Config ;
$Config{useithreads} || die("\n---> Please recompile Perl with \<ithreads\> included. \n") ;
# IP parameterization of network elements.
my %device_ip = (
"core" => "3.3.3.3",
"border" => "5.5.5.5",
) ;
# Initialize devices' pool of threads.
my $index = 0 ;
my #device_thread = () ;
while( my ($key, $value) = each %device_ip )
{
push( #device_thread, threads->new(\&thread_job($key, $device_ip{$key}, $index))->join ) ; $index = $index+1 ;
}
# Worker thread subroutine.
sub thread_job
{
my ($device, $ip, $index) = #_ ;
my $ithread = threads->tid() ;
print "[id=$ithread # $index] : IP address \"$ip\" corresponds to device \"$device\". \n" ;
}
i would be thankful, if someone could help me overcome this problem.
thank you.

The first argument to threads->new() must be a code reference or the name of a function. You are executing the function and try to take a code reference of the result (which is most likely a true value since that is what print returns), hence the error. I guess your call should be like this:
threads->new(\&thread_job, $key, $device_ip{$key}, $index)->join

\&thread_job($key, $device_ip{$key}, $index) doesn't do what you think it does: it runs thread_job(...) immediately, then produces a reference to its result. threads->new then tries to execute that reference inside the new thread, which doesn't work because it's not a reference to a sub.
You probably want to say sub { thread_job($key, $device_ip{$key}, $index) } instead. (Or #musiKk's version.)

Related

Get a symbol's value by its name in a sub

I'm making a package, where I have to get a symbol's value by its name in a sub, while the symbol is defined outside the sub.
Here is the simplified code, it works as expected:
#! /usr/bin/env perl6
sub dump_value($symbol) {
say ::("$symbol")
}
# usage:
my $x = 10;
dump_value('$x');
# expected output: 10
# actual output: 10
Then I put the 'dump_value' in a standalone file as below:
# somelib.pm6
unit module somelib;
sub dump_value($symbol) is export {
say ::("$symbol")
}
# client.pl6
#! /usr/bin/env perl6
use lib ".";
use somelib;
my $x = 10;
dump_value('$x');
The compiler complained:
No such symbol '$x'
in sub dump_value at xxx/somelib.pm6 (somelib) line 3
in block <unit> at ./client.pl6 line 8
Following are some experiments. None of them succeeded.
say ::("MY::$symbol")
say ::("OUR::$symbol")
say ::("OUTER::$symbol")
say ::("CLIENT::$symbol")
...
So how to fix the code?
UPDATE:
Thank you! CALLERS::($symbol) solved my original problem. But in a bit more complex situation, the complier complained again:
# somelib.pm6
unit module somelib;
sub dump_value(#symbols) is export {
# output: 6
say CALLERS::('$x');
# error: No such symbol 'CALLERS::$x'
say #symbols.map({ CALLERS::($^id) } )
}
# client.pl6
#! /usr/bin/env perl6
use lib ".";
use somelib;
my $x = 6;
my $y = 8;
dump_value(<$x $y>);
UPDATE AGAIN:
use OUTER::CALLERS::($^id).
UPDATE AGAIN AND AGAIN:
After I put the 'dump_value' in another sub, it didn't work any more!
# somelib.pm6
unit module somelib;
sub dump_value(#symbols) is export {
say #symbols.map({ OUTER::CALLERS::($^id) } )
}
sub wrapped_dump_value(#symbols) is export {
dump_value(#symbols)
}
#! /usr/bin/env perl6
use lib ".";
use somelib;
my $x = 6;
my $y = 8;
# ouput: (6 8)
dump_value(<$x $y>);
# error: No such symbol 'OUTER::CALLERS::$x'
wrapped_dump_value(<$x $y>);
According to the documentation:
An initial :: doesn't imply global. Here as part of the interpolation
syntax it doesn't even imply package. After the interpolation of the
::() component, the indirect name is looked up exactly as if it had
been there in the original source code, with priority given first to
leading pseudo-package names, then to names in the lexical scope
(searching scopes outwards, ending at CORE).
So when you write say ::("$symbol") in dump_value() in the somelib package, it will first lookup $symbol in the current scope, which has value '$x' then try to look up $x (also in the current scope), but the variable $x is defined in the caller's lexical scope, so you get the No such symbol '$x' error.
You can refer to the caller's lexical symbol given by the value of $symbol using either:
CALLER::MY::($symbol); # lexical symbols from the immediate caller's lexical scope
or
CALLERS::($symbol); # Dynamic symbols in any caller's lexical scope
see the package documentation page.
Couple of things:
use lib ".";
use somelib;
our $x = 10; # You need to export the value into the global scope
dump_value('$x');
Then, use the global scope:
unit module somelib;
sub dump_value($symbol) is export {
say GLOBAL::("$symbol")
}

how to define a var in C++

This code compiles perfect:
if ( args.Length() > 0 ) {
if ( args[0]->IsString() ) {
String::Utf8Value szQMN( args[0]->ToString() ) ;
printf( "(cc)>>>> qmn is [%s].\n", (const char*)(* szQMN) ) ;
} ;
} ;
But this one does not :
if ( args.Length() > 0 ) {
if ( args[0]->IsString() ) {
String::Utf8Value szQMN( args[0]->ToString() ) ; // <<<< (A)
} ;
} ;
printf( "(cc)>>>> qmn is [%s].\n", (const char*)(* szQMN) ) ; // <<<< (B)
Error says : "error C2065: 'szQMN' : undeclared identifier" on line (B)
This means to me that the sentence marked (A) is a definition at the same time as an assignement, right ?
And compiler decides it is "conditionally" defined as it is within two "IF's" ?
My question is : how to move the declaration out of the two "IF's" ?
In this way I also can give it a defalut value ... in case a IF fails.
If I write this line out of the two "IF's"
String::Utf8Value szQMN ("") ;
... then I get the error :
cannot convert argument 1 from 'const char [1]' to 'v8::Handle<v8::Value>'
Any ideas?
This means to me that the sentence marked (A) is a definition at the same time as an assignement, right?
Technically it is a constructor call that creates a variable and initializes it.
Also note that automatic variables exist only until the end of the scope (usually a block inside {} brackets). That is why your second code example does not compile.
if (condition)
{
int x = 5;
}
x = 6; // error, x does not exist anymore
My question is : how to move the declaration out of the two "IF's"?
String::Utf8Value szQMN ("");
This is a constructor call of the class String::Utf8Value class. From the error message it takes a parameter of type v8::Handle<v8::Value>. Without knowing what this is I cannot give you an answer how to call it. You wanted to pass "" which is of type const char* or const char[1] and the compiler is telling you that it does not take that parameter.
Edit:
From the link that DeepBlackDwarf provided in the comment, this is how you create a Utf8Value from a string:
std::string something("hello world");
Handle<Value> something_else = String::New( something.c_str() );
So in your case you would do:
String::Utf8Value szQMN (String::New(""));
the definition in the IF's loop is only works in this loop.
So in the (B) sentence,the definition has already been expired.
If you need to use the var both in the IF's loop and outside,you can declare a global variability by this sentence :
extern String::Utf8Value szQMN( args[0]->ToString() ) ;

perl: doesnt exit without pressing "enter"

use threads;
use threads::shared;
use Term::ReadKey;
sub input_worker {
local $SIG{'KILL'} = sub { threads->exit(0); return;};
while (1) {
if (defined(my $char = ReadKey 0, *STDIN)) {
print "$char";
}
}
return;
} ## end sub input_worker
my $in_thr = threads->create(\&input_worker);
sleep 5;
my $rc = $in_thr->kill('KILL')->join();
print "$rc\n";
This program wont exit by itself and just hangs.
It will only exit after pressing "enter"
How can i make it so that it will exit by itself after 'kill' is signaled
P.S. I dont want to use detach();
Mixing signals and threads is a bit of a challenge, simply because $thread->kill doesn't actually use real signals (since signals are sent to processes, not threads). Which is just as well, because if it did, SIGKILL can break things.
Even when talking about 'normal' signals - you will have slightly unexpected behaviour, because of perl's handling of them See: perlipc . It's not impossible to use, but you need to be aware of the caveats involved.
But the root of the problem is - that the signal is handled safely, which means perl waits until a suitable moment to process it. It will not do this during a 'read' operation, so the signal processing will get deferred.
I think likely what is happening here is your ReadKey is not a nonblocking operation like you think it is. With reference to the Term::ReadKey manpage
ReadKey MODE [, Filehandle]
Takes an integer argument, which can currently be one of the following values:
0 Perform a normal read using getc
-1 Perform a non-blocked read
>0 Perform a timed read
So what it does instead is - starts reading from STDIN, and blocks (ignoring signals) until you press enter. At which point it runs your signal handler.
Given what you're trying to do here - I would suggest you don't want to use signals at all, and instead - just use a shared variable.
Something like this:
use threads;
use threads::shared;
use Term::ReadKey;
my $done : shared;
sub input_worker {
while ( not $done ) {
if ( defined( my $char = ReadKey( -1, *STDIN ) ) ) {
print "$char";
}
}
return;
} ## end sub input_worker
my $in_thr = threads->create( \&input_worker );
sleep 10;
$done++;
my $rc = $in_thr->join();
print "$rc\n";
Will terminate after the timeout, and because it's doing nonblocking reads, it'll bail out on time, without input. You should note though - this thread is going to be 'spinning' looping rapidly waiting to see if input has been pressed - so it's not very CPU efficient. (a small delay in the cycle helps immensely there, say 0.1s).

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

How do you share arrays in threaded perl?

Inside the below sub (a simplified version of code causing an error), each thread should be adding to a master output list. While inside the sub, the array seems to be populating, but when I get back to the main calling portion, it’s empty again. What have I done wrong?
#!/usr/bin/env perl
use threads;
use strict;
my $num_threads = 8;
my #threads = initThreads();
our #outputArray;
foreach(#threads){
$_ = threads->create(\&do_search);
}
foreach(#threads){
$_->join();
}
print "#outputArray";
sub initThreads{
# An array to place our threads in
my #initThreads;
for(my $i = 1;$i<=$num_threads+1;$i++){
push(#initThreads,$i);
}
return #initThreads;
}
sub do_search{
my $id = threads->tid();
push(#outputArray,$id);
threads->exit();
}
According to the threads::shared documentation that #mpapec cited
By default, variables are private to each thread, and each newly
created thread gets a private copy of each existing variable.
So the solution is the module:
use threads::shared ;
our #outputArray :shared ;
There are other forms you can use and a lot of limitations, so reading the entire document is recommended.

Resources