in reply to POE me (Web Cam scripting Trouble)

rlb3 asked about this in #poe (available on most major IRC networks). Here are the findings for the benefit of people reading on PerlMonks.

The code has two major problems. Both of them are in these three (simplified) subroutines:

sub check { print "Check\n"; $_[KERNEL]->delay(move_pic => 3); $_[KERNEL]->delay(get_pic => 1); } sub get_pic { print "get_pic\n"; $_[KERNEL]->yield('check'); } sub move_pic { print "move_pic\n"; $_[KERNEL]->yield('check'); }

The first problem is the one rlb3 noticed: move_pic() was not being triggered. The first call to $kernel->delay(move_pic => 3) sets a timer named move_pic for three seconds in the future. Subsequent calls refresh the timer, resetting it for three seconds into the new future. There's never enough time for move_pic() to be called because check() (triggered via get_pic()) refreshes its timer every second.

Assuming the code is modified so both get_pic() and move_pic() are called, there's another problem. Each check() call would trigger both get_pic() and move_pic(). And each of those functions would trigger check() again. Every iteration would see check() called twice, the second call clobbering the timers created by the first. Without the clobbering, you would see a geometrically increasing number of events. As it is, the code just calls check() twice as often as it should.

A better idea is to break the two operations into separate delay loops:

sub start { $_[KERNEL]->delay(get_pic => 10); $_[KERNEL]->delay(move_pic => 30); } sub get_pic { print "get_pic\n"; $_[KERNEL]->delay(get_pic => 10); } sub move_pic { print "move_pic\n"; $_[KERNEL]->delay(move_pic => 30); }

Each new delay is triggered by the previous one being handled. This is simpler, more direct, and less prone to nasty problems.

Have fun!

-- Rocco Caputo - http://poe.perl.org/