in reply to Thoughts on how to devise a queryable win32 service

My thought is to have the service start a new thread that handles socket connections and responses while the main thread runs the looping processes. Would it be hard for it to view some main thread variables to obtain status?

No, no problem at all. Just share the variables that you want the status thread to be able to see, and add:

my $sharedVar : shared; .... { lock( $sharedVar ); #do stuff with $sharedVar }

around each access to those shared variables in both pieces of code.

If your going to use a package like IO::Socket::INET to provide the communications within the status thread, require it within that thread rather than useing it at the top of the script.

In essence that is all there is to it.

There are some limitations about what types of variable can be shared--filehandles (hackable) and objects or tied vars (not easily hackable)--but that needn't be a great limitation.

Does anyone have any thoughts on a direction for this task?

From your description so far, using a thread would seem the ideal route to me.

Of course, the devil is in the detail--in this case, the detail of exactly what information you want to share between the threads.


Examine what is said, not who speaks.
Silence betokens consent.
Love the truth but pardon error.

Replies are listed 'Best First'.
Re^2: Thoughts on how to devise a queryable win32 service
by noslenj123 (Scribe) on Feb 09, 2005 at 15:13 UTC
    Your Monkness,

    I apparently don't understand a scoping or access issue with trying to access my main program's variable from the thread subroutine. I have:

    use strict; use Thread; my $time : shared; my $t = Thread->new(\&listener,\$time); while (1) { $time = localtime; print $time,"\n"; sleep 1; } sub listener { my $time_ref = shift; while (1) { { lock($$time_ref); print "\tThread time: [$time]\n"; print "\tThread time: [$main::time]\n"; print "\tThread time: [$$time_ref]\n"; } sleep 3; } }
    Which prints out:

    Wed Feb 9 08:06:02 2005 Thread time: [] Thread time: [] Thread time: [] Wed Feb 9 08:06:03 2005 Wed Feb 9 08:06:04 2005 Wed Feb 9 08:06:05 2005 Thread time: [] Thread time: [] Thread time: [] Wed Feb 9 08:06:06 2005
    Indicating to me that the thread only sees the initial value like it has it's own copy. Is that right? How do I access the main threads $time var? Hmmmmm.

      You had me going there for a few seconds--everything in your program seemed legit at first glance;

      Problems:

      1. You are useing "Thread": Don't!

        The Thread module relates to an early attempt at threading in Perl (called perl5005threads). These were deemed a failure and are "going away" in the next release.

        It has been superceded by Ithreads via the threads module.

        It requires at least 5.7.?, but you should not try to use them with any version < 5.8.4 -- get 5.8.6 if you can.

      2. You also need to be using threads::shared if you wish to share variables between threads.
      3. You don't need to pass a reference to $time into your thread sub, once it is shared, it can be seen from any thread (provided it was declared before the thread sub is instantiated.
      4. For correctness, you should be locking your shared variables in both (all) threads.

        In (my) reality, if you are running in a single CPU machine, read references do not appear to need locks be applied as only one thread can be running at a time, but if you move the code without locks to a multiprocessor machine you would likely get bitten.

        In theory, even on a single processor machine, it is possible that one thread could be in the process of writing to a shared variable and have not completed the update when it gets suspended. If it did not apply locks, or another thread reading it does not apply them (and thereby get suspended until teh write is completed), then the other thread could read a partially updated variable that is not in an internally coherent state and get bad data or even segfault.

        To date, try as hard as I might, even running long running, backtracking regexes on huge shared strings, I have never been able to make this happen.

        ( For the pedantic: The above statement is only true: on my single processor, win32 machine; in my house; whilst I've been watching; etc. etc. etc.....Yet! ;)

      use strict; use threads; use threads::shared; my $time : shared; sub listener { my $array_ref = shift; while (1) { { lock $time; print "\tThread time: [$time]\n"; } { lock($array_ref); print "\tThread time: [@$array_ref]\n"; } sleep 3; } } my @array : shared; my $t = threads->new( \&listener, \@array ); while (1) { { lock $time; $time = localtime; } print $time,"\n"; { lock @array; push @array, $time; } sleep 1; } __END__ [16:09:17.53] P:\test>429405 Wed Feb 9 16:09:31 2005 Thread time: [Wed Feb 9 16:09:31 2005] Thread time: [] Wed Feb 9 16:09:32 2005 Wed Feb 9 16:09:33 2005 Thread time: [Wed Feb 9 16:09:33 2005] Thread time: [Wed Feb 9 16:09:31 2005 Wed Feb 9 16:09:32 200 +5 Wed Feb 9 16:09:33 2005] Wed Feb 9 16:09:34 2005 Wed Feb 9 16:09:35 2005 Wed Feb 9 16:09:36 2005 Terminating on signal SIGINT(2)

      I switched your code around a bit not because there was anything wrong with the ordering, but to allow me to demonstrate a couple of points.

      I've stopped passing the scalar ref to the sub and am passing a reference to an array that is also updated in the main thread.

      Because $time is visible to your listener() sub, it is accessible, via closure in the normal way, without being explicitly passed it to the thread.

      The array however, was not existing when the sub was declared, so it must be passed explicitly.

      Basically, all the normal perl scoping rules apply--once you are using the correct modules :) I should have mentioned that before. Sorry!


      Examine what is said, not who speaks.
      Silence betokens consent.
      Love the truth but pardon error.
        I grovel. Must you be so simply clear? LOL Indeed, I had already figured out that I must not use 'Thread' but I didn't know why. Thanks for pointing it out.

        I had shifted to 'threads' and my code looked almost exactly like yours as I bagged the references and employed locking in both threads.

        Thanks also for pointing out that the array would not be known yet and must be 'blessed' so to speak. I have it working now, on to the next lesson.

        Seems the more I learn, the less I know.....grrrr!

        I thought I read somewhere that Perl internally made sure any shared data accessed by threads would be in a consistent state, no matter if you lock the shared variable or not. In fact, I seem to recall it said it was quite safe to have one thread push stuff onto a shared array (ie, a queue), and another shift stuff off the other end of it, safely without any locking. Are you saying that on an SMP box the en-queue side might end up pushing garbage data onto the shared array, or that the de-queue side might read garbage data? Obviously it's okay if the reader side doesn't see anything yet, so long it just thinks that queue is undefined (empty) and just sleeps a while and checks again later on...
      In my humility I guess I don't know the difference between 'Thread' and 'threads'. After shifting the code to use 'threads' and 'threads::shared', I am able to access my variable. What the heck is the 'Thread' module for then?