Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

How do you share an object(Telnet Session) between threads?

by jmlynesjr (Deacon)
on Sep 29, 2015 at 17:43 UTC ( [id://1143355]=perlquestion: print w/replies, xml ) Need Help??

jmlynesjr has asked for the wisdom of the Perl Monks concerning the following question:

How do you share an object(Telnet Session) between threads?

Update: I have a working version of this app using one Telnet Session thread along with the Wx GUI code. I will post this version to the Cool Uses for Perl section.

I need the Telnet session below available to 3 threads(connect, disconnect, & scan). $telnetsession is of type Net::Telnet per print(ref($telnetsession)).

This is part of a larger wxPerl script. All of the display and interlocking between the GUI and threads seems to working corectly.

Crossposted to wxperl-users.

Thanks, James

# Define the Thread shared data area - All threads access this scaler +data fine my %common : shared; $common{ip} = "127.0.0.1"; # Localhost $common{port} = "7356"; # Local Port as defined in gqrx $common{telnetsession} = 0; # Object Pointer ??? Problem ?? +? $common{tnerror} = 0; # Status $common{connect} = 0; # Command $common{connected} = 0; # Status $common{disconnect} = 0; # Command $common{scanstart} = 0; # Command $common{scanstarted} = 0; # Status $common{beginf} = 0; # Scan - Beginning Frequency $common{endf} = 0; # Scan - Ending Frequency $common{step} = 0; # Scan - Frequency Step $common{squelch} = 0; # Scan - Minimum RSSI(Recieved Signal + Strength Indicator) $common{rssi} = 0; # Scan - Latest RSSI $common{pause} = 0; # Scan - Time between scans - msec $common{listen} = 0; # Scan - Time to Listen to a strong si +gnal - msec $common{mode} = 0; # Scan - Demodulator Type $common{stopthreads} = 0; # Command # Connect the Telnet Session - #1 sub Connect { while(1) { if($common{stopthreads}) {print "\nConnect Thread Terminated\n +"; return}; if($common{connect}) { if(!$common{connected}) { print "Open Telnet Connection to gqrx\n"; my $telnetsession = Net::Telnet->new(Timeout => 2, port + => $common{port}, Errmode => sub {$common{tnerro +r} = 1;}); $telnetsession->open($common{ip}); $common{telnetsession} = shared_clone($telnetsession); + # Line 92 Errors $common{connected} = 1; $common{connect} = 0; } } threads->yield(); } }
Error message: Thread 1 terminated abnormally: Unsupported ref type: GLOB at ./thread +edgqrxLite.pl line 92 thread 1

James

There's never enough time to do it right, but always enough time to do it over...

Replies are listed 'Best First'.
Re: How do you share an object(Telnet Session) between threads? (clone handle)
by tye (Sage) on Sep 29, 2015 at 18:25 UTC

    If you had 3 non-Perl threads, then you could share your Net::Telnet object between the threads so long as only one thread was allowed to access it at a time. Three Perl threads means 3 separate instances of the Perl interpreter. Which means sharing between them involves making 3 copies of every piece of the object. threads::shared knows how to do that for simple data. It can't just do it automatically for you in the case of things containing file handles.

    You should be able to work around this limitation if you do your own locking to prevent simultaneous access and take steps to prevent problems from multiple copies each trying to tear down the file handle... if the module doesn't leak state outside of the object. For example, using buffered I/O would leak information into the per-interpreter buffer. Or storing some state information in an (unshared) class-global structure would be a problem.

    So, you'd have to inspect the guts of the object to figure out where the file handle is stored. Remove the file handle before calling shared_clone(). Share the fileno of that handle. In each thread, put a clone of the file handle back via something like:

    open my $clone, '+<&=', $fileno or die ...;

    - tye        

      Tye, I don't think the locking will be an issue. The shared flags seem to be working fine. I don't currently have the internals knowledge to implement your suggestion. I found a BrowserUK reply concerning sharing file handles between threads. How do I get the filehandle out of the Telnet object? When I print Dumper $telnetsession, I get,

      $VAR1 = bless( \*Symbol::GEN0, 'Net::Telnet');

      I would be nice to figure this out and get it documented

      Thanks for your response.

      James

      There's never enough time to do it right, but always enough time to do it over...

        In that case you need to look at the several things in the glob (a scalar, a hash, an array, a file handle, maybe a few other more exotic things but unlikely) and see which are being used by the object. Share each of those and then, in each thread, build a new glob and put the shared things into it (and then bless the result).

        - tye        

Re: How do you share an object(Telnet Session) between threads?
by BrowserUk (Patriarch) on Sep 29, 2015 at 19:12 UTC
    I need the Telnet session below available to 3 threads(connect, disconnect, & scan).

    What is the purpose of sharing one session between 3 threads?

    The reasoning behind my question:

    1. If 3 threads (or processes; this isn't a "threads flaw") try to communicate via a single session concurrently:

      then their communications will all interfere with each other and the remote session will just become corrupted and fail.

    2. If the idea is to interlock the session so that only one of the threads can communicate at any given time and doesn't unlock the session to the other threads until it has completed its transactions:

      Then it make no sense to share the telnet session; you'd just be making life hard for yourself.

      Far better to start a fourth thread that has a input queue.

      Have the three threads queue the information required to perform their requests; the fourth thread issues the request via its single, unshared telnet session; and then return the results to the calling thread.

      The serialisation is automatic and efficient; and you avoid all the complications and risks of sharing a complex object.

    That said; telnet servers are designed to host multiple sessions. The simplest solution would be to have each of your threads starts its own unshared session to the remote telnet server and let it do what it is designed to do.

    If you have a reason not covered by the above for wanting to share a single telnet session; please identify it.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority". I knew I was on the right track :)
    In the absence of evidence, opinion is indistinguishable from prejudice.
    I'm with torvalds on this Agile (and TDD) debunked I told'em LLVM was the way to go. But did they listen!

      BrowserUK, it seemed like the thing to do at the time. At least until the shared object issue bit me. Only one thread needs to use the connection at a time, so collapsing 3 down to 1 makes sense. I appreciate your explanation.

      Update: Fixed spelling error.

      James

      There's never enough time to do it right, but always enough time to do it over...

Re: How do you share an object(Telnet Session) between threads?
by SuicideJunkie (Vicar) on Sep 29, 2015 at 18:19 UTC

    Do you want to share the connection itself, or just have an interface that other threads can use to request that the owner of the connection do things on their behalf (presumably with some queuing to prevent mixing messages and mangling command sequences)

      I had wanted to share the connection. In the docs I had seen where a reference could be shared, however, I obviously overlooked the "gottcha" that only references to shared scalers are supported. Then I found the doc on shared_clone that seemed to be able to share objects, but it errors also.

      The connect, disconnect, and scan threads are being triggered by shared flags set from Wx button events. I could collapse these threads into one connection server thread and run code sections based on the existing flags. I had pondered that earlier today, but was hoping to avoid rewrite #3.

      I have a non-threaded version that works except for a sequence of button pushes that gets the state confused because of what seems to be async processing of the Telnet connection error. There is a delay in setting the error flag which the event sub mishandles. Thus this second approach.

      Thanks for your response.

      James

      There's never enough time to do it right, but always enough time to do it over...

Re: How do you share an object(Telnet Session) between threads?
by Anonymous Monk on Sep 29, 2015 at 19:23 UTC
    Ahem ... At the risk of stating the very-obvious ... how does the remote(!) see this? And, can The Remote possibly, and consistently(!), algorithmically(!!), figure this out?!?!

      I have no control over the remote. It's a software defined radio(SDR) application(gqrx) that provides for remote control via a Telnet connection using a subset of the amateur radio RigControl protocol. I'm just implementing a scanner function on top of the basic app. I tried to keep these details out of the discussion as they don't apply to the OP.

      James

      There's never enough time to do it right, but always enough time to do it over...

Re: How do you share an object(Telnet Session) between threads?
by sundialsvc4 (Abbot) on Sep 30, 2015 at 05:21 UTC

    As BrowserUK ably suggests, when a thread is dedicated to the care-and-feeding of any external resource or host connection, it can be reliably programmed to deal with any eventuality, and to always know the state of that connection.   Even if you decided to open multiple telnet sessions, I would still have a controller-thread (instance ...) dedicated to each one, which accepted requests and delivered results using thread-safe queues.   A finite-state machine (FSM) is an excellent design for this piece.   A second queue can be used to communicate status to the parent thread, analogous to the separate STDERR output-stream of an ordinary Unix process.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1143355]
Approved by planetscape
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others chilling in the Monastery: (5)
As of 2024-04-23 13:24 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found