Boost logo

Boost :

From: Christopher Kohlhoff (chris_at_[hidden])
Date: 2005-12-29 07:13:51


Hi Andrew,

--- Andrew Schweitzer <a.schweitzer.grps_at_[hidden]> wrote:
<snip>
> I suppose what I meant was that in order to prevent the timer
> from dispatching when the deadline_timer goes out of scope you
> have to prevent the deadline_timer from destructing, which
> probably often means dynamically allocating it.
>
> Now that I think about it... how are you expecting the
> deadline_timer object to be used? I assume it shouldn't just
> go out of scope. Since we might want to keep it around to
> cancel, presumably we shouldn't pass it to the handler to
> delete, or we could be canceling a deleted object... although
> this is what I'm actually doing in my code.... So are you
> expecting some data structure to keep it around? And then how
> should it be cleaned up?

In my experience a timer is often a data member of a class where
the objects are relatively long-lived, e.g. a class used to
manage a connection. The same timer is often reused by adjusting
the expiry time and reissuing an asynchronous wait. There's no
need to clean up the timer if there are no asynchronous waits on
it.

You can allocate a timer dynamically for a single asynchronous
wait if you want, but this is not required.

> A related question: how do you ask whether a timer is still
> running? I think you could call expires_at() and compare to
> current time. It looks like there might be two issues with
> this: 1) Will crash if the timer is expired? (haven't tried
> just took a quick look at code). 2) Oddly enough getting the
> current time can be quite expensive, for example on Wince (I
> think because you have to get data from the kernel). It might
> be a lot faster to just say "I'm expired" if impl_ is null.

For applications that need to know whether the timer has fired
(for use cases other than cancelling the timer) the best thing
to do is probably just to set some state in the timer's
associated handler.

It might help to keep in mind that a timer is really no more
than an expiry time. Because of that, explicitly checking
whether a time object has expired must involve a comparison with
the system time. An asynchronous wait on the timer is a request
to be informed when the timer's expiry time has passed, and
except for cancellation is decoupled from the timer itself.

> Good question. At this point I don't see our use case
> occurring with asio. It's what I'm used to, and it seems like
> a good idea, possibly just from habit, but maybe there's an
> underlying reason. I think it comes down to whether the user's
> context usually naturally provides enough easily bindable data
> to differentiate between past and multiple current executions
> of the handler. Also, I think this data might need to be
> stored by the user outside of the deadline_timer so that the
> user can decide which timer to cancel, or check which timers
> are running. My sense is that by invoking the same code over
> and over again asynchronously we are just asking to be
> confused about which invocation we are in. It might be nice if
> the library just generated a unique 32 or 64 bit value for
> each timer. Or maybe that's more trouble than it's worth.

In applications I have seen using asio, the cancellation
protocol I outlined in my other response has been sufficient.

What I think you're talking about is more accurately described
as an async_wait id. For example, you could do something like
this:

class foobar
{
  ...

  int async_wait_id_;
  deadline_timer timer_;

  void start_new_wait()
  {
    timer_.cancel();
    timer_.expires_at(...);
    timer_.async_wait(
        boost::bind(
          &foobar::handle_timeout,
          ++async_wait_id_));
  }

  void handle_timeout(int my_wait_id)
  {
    if (my_wait_id == async_wait_id_)
    {
      // This was the active wait ...
    }
  }
};

Cheers,
Chris


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk