in reply to AnyEvent: How to protect critical sections?

If you have code you don't want interrupted, don't yield to AnyEvent functions, it's that simple.

AnyEvent does not run anything in parallel, so as long as you are running your own Perl code, and not calling ->recv, ->send or ->timer, the AnyEvent loop won't run and your code will stay in the critical section uninterrupted.

Replies are listed 'Best First'.
Re^2: AnyEvent: How to protect critical sections?
by saintmike (Vicar) on May 17, 2011 at 20:37 UTC
    I understand, but the problem is that I have two competing tasks: One is the timer firing, the other is a http request callback having data available.

    I simply don't want the timer callback to be executed while the http request is under way, but *right after*.

    I guess I could just restart the timer and try to execute the interrupt later, but that's a) non-deterministic because it could fail again and b) not very efficient because I'd like to run it as soon as the http request has been completed.

      Then I would cancel the timer when starting the HTTP request, and relaunch the timer in the HTTP request on_body callback (and likely in the on_error callback too). You can "immediately" launch a timer by launching it with after => 0 - this will launch the timer callback the next time the event loop is entered.

        Nice idea, that could actually work, I'll try that in a minute.

        I was just hoping that there was some kind of $condvar->send/recv mechanism that supported lock()/unlock() so that I could write something like

        $condvar->lock(); http_get "http://blah", sub { $condvar->unlock(); print $_[1] };

        sub timer_callback { $condvar->lock(); # ... $condvar->unlock(); }
Re^2: AnyEvent: How to protect critical sections?
by Anonymous Monk on May 18, 2011 at 20:00 UTC
    (i would have liked to reply to the original posting, but there is no reply button, apparently). I don't know what the "bets" way is, but one can simply use a global variable. Simple case
    { local $ignore_interrupt = 1; ... } ... return if $ignore_interrupt;
    That loses "interrupt" events, which might not be acceptable. A solution for that is to store some marker in the variable.
    { local $ignore_interrupt = 1; ... do_interrupt if $ignore_interrupt == 2; } ... if ($ignore_interrupt) { $ignore_interrupt = 2; } else { do_interrupt; }
    The same kind of code also works in Coro. However, I firmly believe that youc an always find a simpler way - e.g. by stopping and restarting the timer or similar code. Trying to recursive into the event loop somehow creates modality, which is kind of evil and tends to lead to more problems than it solves.