Re: multiple infinitive loops
by BrowserUk (Patriarch) 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
| [reply] [d/l] |
|
|
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
| [reply] |
Re: multiple infinitive loops
by ikegami (Patriarch) 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);
}
| [reply] [d/l] |
|
|
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
| [reply] |
|
|
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);
}
| [reply] [d/l] |
|
|
|
|
|
|
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.
| [reply] |
Re: multiple infinitive loops
by TheEnigma (Pilgrim) on Oct 06, 2004 at 15:28 UTC
|
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.
| [reply] [d/l] |
|
|
sub to_be {
print "be ";
goto &to_do;
}
sub to_do {
print "do ";
goto &to_be;
}
to_do();
or you'd run out of memory FAST.
| [reply] |
|
|
while(1) {
foo();
bar();
}
Since we are doing no-threading, no-forking examples, this eats cheesy poofs and is still lame. | [reply] [d/l] |
|
|
| [reply] |
|
|
| [reply] |
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. |
| [reply] [d/l] |
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.
| [reply] |
|
|
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
| [reply] |
Re: multiple infinitive loops
by pg (Canon) on Oct 07, 2004 at 03:06 UTC
|
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";
}
}
| [reply] [d/l] |
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 | [reply] [d/l] |
|
|
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
| [reply] [d/l] [select] |
|
|
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
| [reply] |
|
|
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
| [reply] [d/l] |
|
|
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
| [reply] |
|
|
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 );
}
| [reply] [d/l] |