Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

multiple infinitive loops

by ozkaa (Acolyte)
on Oct 06, 2004 at 15:09 UTC ( #397011=perlquestion: print w/replies, xml ) Need Help??

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

Hello,

I am looking for a way to do 2 or more multple while(1)'s at the same time.

<EXAMPLE> #!/usr/bin/perl sub 1 { while(1) { print "in sub 1 \r\n"; } sub 2 { while(1) { print "in sub 2 \r \n"; } } &sub1(); &sub2(); output : in sub 1 in sub 2 (endless :p)


I need it because I have 2 infinitive loops with each a event handler in it, and both of them must act when an event is received.

I tried POE and Threading without success, anybody ?

Thanks
Oscar

Replies are listed 'Best First'.
Re: multiple infinitive loops
by BrowserUk (Pope) on Oct 06, 2004 at 15:12 UTC
    I tried POE and Threading without success,...

    Either is capable of doing what you've asked for. If you've had trouble it's because you've done it wrong. Why not show us your attempt(s) and let us help you correct them?

    Update: Just to show how easy it could be:

    #! perl -slw use strict; use threads qw[ async ]; sub sub1 { while(1) { print "in sub 1"; select undef, undef, undef, 0.1; } } sub sub2 { while(1) { print "in sub 2"; select undef, undef, undef, 0.1; } } async \&sub1; sub2;

    Of course, it's not very useful, but then niether is the spec :)


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "Think for yourself!" - Abigail
    "Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon
      i posted some coding at the bottom, its not the same, but should give a clear view of what i'm trying to do

      Oscar
Re: multiple infinitive loops
by ikegami (Pope) on Oct 06, 2004 at 15:24 UTC

    Threading is the obvious solution -- we'll help you if you show us what you tried -- but there might be alternatives. What kind of events are these?

    Are they filehandles? Look at select() or its OO counterpart IO::Select. This only works on sockets in Windows, but there's a workaround to produce selectable pipes.

    Are you on Windows? If these are Windows events or could be wrapped by a Windows event, you could access WaitForMultipleEvents via some Win32 module.

    Can you specify a timeout? If so, you could use:

    while(1) { Sub1(TIMEOUT); Sub2(TIMEOUT); }
      Thanks for all the replies :)

      Im on windoze and using the
      Win32::OLE("WbemScripting.SWbemLocator");

      There is an event handler on it ExecNotificationQuery()->NextEvent();

      Which is locking everything up.

      I tried using a async threads but it still locks on the event.

      I will look at the WaitForMultipleEvents

      Many Thanks,
      Oscar

        I don't know anything about these scripting/locator things, but a quick look at the MSDN Library shows that NextEvent accepts a timeout. Therefore, a simple solution is:

        use constants TIMEOUT => 50; use constants wbemErrTimedOut => 0x80043001; while (1) { $o1 = $h1->NextEvent(TIMEOUT); ProcessEvent1($h1, $o1) if ($o1 != wbemErrTimedOut); $o2 = $h2->NextEvent(TIMEOUT); ProcessEvent2($h2, $o2) if ($o2 != wbemErrTimedOut); }
        I was working on a perl script under windows recently and found that it blocked (wouldn't even time out) while attempting to connect to a network socket (This wasn't a problem on other platforms.). I ended up forking a child process to attempt the connection, and having the parent kill it if it went too long. From what you've shown so far, I would suggest trying to fork a child process for each of those event-handling tasks. That would allow both event handlers to be available and avoid blocking everything when one process blocks.
Re: multiple infinitive loops
by TheEnigma (Pilgrim) on Oct 06, 2004 at 15:28 UTC
    infinitive loop???

    sub to_be { print "be "; &to_do; } sub to_do { print "do "; &to_be; } &to_do;

    Sorry, I couldn't resist!

    "To be is to do"--Socrates.
    "To do is to be"--Jean-Paul Sartre.
    "Do be do be do"--Frank Sinatra.

    TheEnigma

        while(1) { foo(); bar(); }

        Since we are doing no-threading, no-forking examples, this eats cheesy poofs and is still lame.

      The idea is awesome :-)

      However, when one of them receives its event and acts... the other will be prevented from acting for a while... :-) But the idea is wonderful :-)

      Nice tag line :o)

      PJ
      use strict; use warnings; use diagnostics;
Re: multiple infinitive loops
by Plankton (Vicar) on Oct 06, 2004 at 15:22 UTC
    Here's an script based on the fork example in the Camel book:
    #!/usr/bin/perl -w use strict; sub one { while(1) { print "in sub one\n"; sleep 1; } } sub two { while(1) { print "in sub two\n"; sleep 1; } } my $pid; if( $pid = fork ) { one(); } elsif ( defined $pid ) { two(); }

    Plankton: 1% Evil, 99% Hot Gas.
Re: multiple infinitive loops
by pg (Canon) on Oct 07, 2004 at 03:06 UTC

    I tried to make it close to the code in your original post.

    use threads; use strict; use warnings; threads->create(\&foo); threads->create(\&bar); while (1) { sleep(60); } sub foo { while(1) { print "foo\n"; } } sub bar { while(1) { print "bar\n"; } }
Re: multiple infinitive loops
by Joost (Canon) on Oct 06, 2004 at 15:50 UTC
    I need it because I have 2 infinitive loops with each a event handler in it, and both of them must act when an event is received.
    The obvious solution (to me at least) would be to use only one event loop. This might be a problem if you have 2 toolkits with a fixed eventloop implementation, but I think most systems let you have your own code in the loop/write your own event loop. (I know Tk does)

    Joost.

      the eventloop is from win32::ole

      it uses the WbemScripting.SWbemLocator for looking at incoming processes, when a process is recevied it goes back into it's loop.

      It seems to be stuck at that specific event handler :(

      when it reaches the ExecNotificationQuery->NextEvent(); it goes into a loop of its own and nothing is possible afterwards until I break out of it, which I don't want to because its an ongoing process

      Oscar
Re: multiple infinitive loops
by ozkaa (Acolyte) on Oct 06, 2004 at 17:00 UTC
    This is what im trying to archieve

    use strict; use Win32::OLE qw(in); Win32::OLE->Option("Warn"=>3); use threads qw[ async ]; sub check_1 { my $query = "SELECT * FROM __InstanceCreationEvent WHERE TargetIns +tance ISA 'Win32_NTLogEvent' "; my $wbemloc = new Win32::OLE("WbemScripting.SWbemLocator"); $wbemloc->{Security_}->{Privileges}->AddAsString("SeSecurityPrivil +ege"); my $wbemsvc = $wbemloc->ConnectServer(".", "root/cimv2"); $wbemsvc->{Security_}->{ImpersonationLevel} = 3; my $wbemevtsrc = $wbemsvc->ExecNotificationQuery($query); while (1) { my $wbemobj = $wbemevtsrc->NextEvent(); my $msg = $wbemobj->{TargetInstance}->{Message}; $msg =~ s/\t//g; my @array = split(/\r\n/,$msg); my $tst = join(';',@array); $tst =~ s/;;/;/g; print $tst."\n"; } } sub check_2 { my $query = "SELECT * FROM __InstanceDeletionEvent WHERE TargetIns +tance ISA 'Win32_NTLogEvent' "; my $wbemloc = new Win32::OLE("WbemScripting.SWbemLocator"); $wbemloc->{Security_}->{Privileges}->AddAsString("SeSecurityPrivil +ege"); my $wbemsvc = $wbemloc->ConnectServer(".", "root/cimv2"); $wbemsvc->{Security_}->{ImpersonationLevel} = 3; my $wbemevtsrc = $wbemsvc->ExecNotificationQuery($query); while (1) { my $wbemobj = $wbemevtsrc->NextEvent(); my $msg = $wbemobj->{TargetInstance}->{Message}; $msg =~ s/\t//g; my @array = split(/\r\n/,$msg); my $tst = join(';',@array); $tst =~ s/;;/;/g; print $tst."\n"; } } async \&check_1; check_2;



    Its locking at my $wbemobj = $wbemevtsrc->NextEvent();
    The check_2 will not be started :(

    Many Thanks,
    Oscar

      A personal plee, ignore at will. Please insert some horizontal whitespace (and use proper indentation, though I realise that that can get screwed through posting/cutting/pasting).

      sub check_1 { my $query = " SELECT * FROM __InstanceCreationEvent WHERE TargetInstance ISA'Win32_NTLogEvent' "; my $wbemloc = new Win32::OLE( "WbemScripting.SWbemLocator" ); $wbemloc->{ Security_ }{ Privileges } ->AddAsString( "SeSecurityPrivilege" ); my $wbemsvc = $wbemloc->ConnectServer( ".", "root/cimv2" ); $wbemsvc->{ Security_ }{ ImpersonationLevel } = 3; my $wbemevtsrc = $wbemsvc->ExecNotificationQuery( $query ); while( 1 ) { my $wbemobj = $wbemevtsrc->NextEvent(); my $msg = $wbemobj->{ TargetInstance }{ Message }; $msg =~ s/\t//g; my @array = split( /\r\n/, $msg ); my $tst = join( ';', @array ); $tst =~ s/;;/;/g; print $tst."\n"; } }

      More readable than above? I had to resort to sorting the source to determine that check_1 and check_2 were identical.

      Which brings me to my second point. Cut&paste code is bad (bad,bad;), and completely unnecessary. The whole point of subroutines is that you can call them twice or more. (Caveat: closures can complicate this!)

      This works fine.

      #! perl -slw use strict; use threads qw[ async ]; sub sub1 { my $no = shift; while(1) { print "in sub $no"; select undef, undef, undef, 0.1; } } async \&sub1, 1; ## Param = '1' sub1( 2 ); ## Param = '2' __END__ P:\test>397011 in sub 2 in sub 1 in sub 2 in sub 1 in sub 2 in sub 1 Terminating on signal SIGINT(2)

      And that brings up the third point which is speculative because I don't have the "WbemScripting.SWbemLocator" (as far as I am aware) in order to verify this.

      Many OLE .dll's use what I believe is called the 'apartment' model. The in's and out's of this are complicated, off-topic for this place, and I'm not sure I remember them correctly (if I ever did). Breifly, there are various ways of building DLLs, some of which allow that DLL to be called from as many processes, and as many threads within those processes as you like. Ie. they are fully reentrant. Others can only be entered once from within a given process. There are other variations as well--see MSDN for more/better/accurate information.

      The upshot is that it may be that the DLL that provides the OLE object you are calling is not compatible with threading. It would be a good thing to know, before continuing to try do what your doing, if this is the case or not. The best I can suggest is that you consult the docs, or vendor, before expending more energy trying to solve this.

      Alternatively, if you have and know VB, then try doing what your doing from (minimally) from there. If you hang up there too, then you probably have your answer.

      Of course, it may be that your real code doesn't try to access the same identical object/event loop concurrently, and this is just more sample code.

      Ultimately, sample code rarely helps solve real problems.


      Examine what is said, not who speaks.
      "Efficiency is intelligent laziness." -David Dunham
      "Think for yourself!" - Abigail
      "Memory, processor, disk in that order on the hardware side. Algorithm, algorithm, algorithm on the code side." - tachyon
        Thanks for your post
        I am going to try VB tommorow when I get my cd in from work.., then it's M$->M$ combination which probally work, and if not, then the problem is the COM itself... which im not intended to rewrite :p

        Copy/pasting the code was merely for a understanding to people on how I implemented the Win32::Ole thing...

        again, exploring this area, nothing more :p

        Thanks for all your help

        Oscar

      I think you may be onto a loser trying to combine Perl threads and COM (Win32::OLE), unless this has been improved recently. See this article on the ActiveState Win32 mailing list (the post is over a year old - things have moved on a tad since - but the error shown matched the one I received). Dispite this, using fork as shown by Plankton in the earlier example does appear to work for me (i.e. it executes both subs, which is odd, since fork on win32 is implemented with threads...).

      my $pid; if( $pid = fork ) { check_1(); } elsif ( defined $pid ) { check_2(); }

      Hope the mailing list reference helps.

      Cheers,

      -- Dave :-)


      $q=[split+qr,,,q,~swmi,.$,],+s.$.Em~w^,,.,s,.,$&&$$q[pos],eg,print
        hey dave,

        yeah I tried the fork :) but with no luck

        actually the app is getting pretty unpredicatable using this method (i.e.) one time is does it work correctly and the other time it doesn't :D

        I think the win32::ole is a little bit of a P.I.T.A. and I might switch over to M$ vb to check things...,

        Thanks for your input
        Oscar

      Here's a simple way to do it with POE. Keep in mind that there will be at minimum a one second delay before each check for a new event. More importantly, if the NextEvent() calls block (which I'm guessing they do from your code), you could wait longer than one second on a given check, meanwhile events from the other generator could be happening. That's the trouble with blocking calls. I didn't feel like copying 90% of your code, so you'll need to replace the ...'s with the relevant portions.

      #!/usr/bin/perl use strict; use warnings; use POE; POE::Session->create( inline_states => { _start => \&init, check_creation => \&check_creation, check_deletion => \&check_deletion, }, ); $poe_kernel->run(); exit 0; sub init { my ( $kernel, $heap ) = @_[ KERNEL, HEAP ]; # make creation event logger thingie $query = ...; # the creation one ... $heap->{ creator } = $wbemsvc->ExecNotificationQuery( $query ); # make deletion event logger thingie $query = ...; # the deletion one ... $heap->{ deletor } = $wbemsvc->ExecNotificationQuery( $query ); $kernel->delay_set( check_creation => 1 ); $kernel->delay_set( check_deletion => 1 ); } sub check_creation { my ( $kernel, $heap ); my $wbeobj = $heap->{ creator }->NextEvent(); my $msg = $wbeobj->{ TargetInstance }->{ Message }; # ... do the message stuff here $kernel->delay_set( check_creation => 1 ); } sub check_deletion { my ( $kernel, $heap ); my $wbeobj = $heap->{ deletor }->NextEvent(); my $msg = $wbeobj->{ TargetInstance }->{ Message }; # ... do the message stuff here $kernel->delay_set( check_deletion => 1 ); }

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others meditating upon the Monastery: (3)
As of 2021-12-09 03:45 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    R or B?



    Results (36 votes). Check out past polls.

    Notices?