View mode: basic / threaded / horizontal-split · Log in · Help
June 03, 2011
Is this a good way of setting up a timer?
I can't find any timers in phobos, basically I want some loop to run for a predetermined amount of time. Currently I use this:

import core.time;
import std.datetime;
import core.thread;

void main()
{
   auto finalTime = Clock.currTime + dur!"seconds"(4);
   
   while (true)
   {
       Thread.sleep(dur!("seconds")(1));
       if (Clock.currTime > finalTime)
           break;   
   }
}

Is that check doing any conversions in the background, or am I safe (performance-wise)? Well I'm probably wasting performance on waking up the thread every second.. hmm.
June 03, 2011
Re: Is this a good way of setting up a timer?
On 2011-06-03 14:22, Andrej Mitrovic wrote:
> I can't find any timers in phobos, basically I want some loop to run for a
> predetermined amount of time. Currently I use this:
> 
> import core.time;
> import std.datetime;
> import core.thread;
> 
> void main()
> {
> auto finalTime = Clock.currTime + dur!"seconds"(4);
> 
> while (true)
> {
> Thread.sleep(dur!("seconds")(1));
> if (Clock.currTime > finalTime)
> break;
> }
> }
> 
> Is that check doing any conversions in the background, or am I safe
> (performance-wise)? Well I'm probably wasting performance on waking up the
> thread every second.. hmm.

Generally, you'd just put it to sleep for the period of time that you want to 
wait for. The only reason that I see to keep waking it up is if it could be 
interrupted and effectively told to wake up - in which case you would be 
sleeping and waking up over and over again, checking to see if enough time had 
passed or if you had been signaled to stop waiting.

Now, if what you're trying to do is run the code in the loop for a 
predetermined length of time, then you'd just check the time every X 
iterations of the loop. If the loop is short, then X would be larger (to avoid 
asking for the time needlessly often and wasting cycles), whereas if the loop 
is long enough, then X might even be 1.

As your code stands though, I'm not sure what you're really trying to. Oh, and 
by the way, std.datetime publicly imports core.time, so if you import 
std.datetime, you don't need to import core.time.

- Jonathan M Davis
June 03, 2011
Re: Is this a good way of setting up a timer?
On 6/3/11, Jonathan M Davis <jmdavisProg@gmx.com> wrote:
>
> Generally, you'd just put it to sleep for the period of time that you want
> to
> wait for. The only reason that I see to keep waking it up is if it could be
> interrupted and effectively told to wake up - in which case you would be
> sleeping and waking up over and over again, checking to see if enough time
> had
> passed or if you had been signaled to stop waiting.

Yeah, I should have made a better example. Basically I have a loop
that ends either after a specific time period, or it could end by
receiving a signal. I just use a shared book for that, this would be
it:

   while (engineActive)  // shared bool
   {
       if (Clock.currTime > finalTime)
           break;

       Thread.sleep(dur!("seconds")(1));
   }

> Oh,
> and
> by the way, std.datetime publicly imports core.time, so if you import
> std.datetime, you don't need to import core.time.
>
> - Jonathan M Davis
>

Ok thanks!
June 03, 2011
Re: Is this a good way of setting up a timer?
On 2011-06-03 14:37, Andrej Mitrovic wrote:
> On 6/3/11, Jonathan M Davis <jmdavisProg@gmx.com> wrote:
> > Generally, you'd just put it to sleep for the period of time that you
> > want to
> > wait for. The only reason that I see to keep waking it up is if it could
> > be interrupted and effectively told to wake up - in which case you would
> > be sleeping and waking up over and over again, checking to see if enough
> > time had
> > passed or if you had been signaled to stop waiting.
> 
> Yeah, I should have made a better example. Basically I have a loop
> that ends either after a specific time period, or it could end by
> receiving a signal. I just use a shared book for that, this would be
> it:
> 
> while (engineActive) // shared bool
> {
> if (Clock.currTime > finalTime)
> break;
> 
> Thread.sleep(dur!("seconds")(1));
> }

Yeah. That looks fine, though currTime isn't a property (it takes an optional 
TimeZone object), so technically it should have parens. That's obviously not 
enforced at the moment though. In any case, it's essentially fine, but has 2 
potential issues, depending on how accurate you want the timing to be or how 
responsive you want the loop to be in exiting.

First off, you pay no attention whatsoever to how close the current time is to 
the final time such that there could be a few microseconds of difference 
between them and you'd still sleep for a whole second before exiting. If you 
want it to be more accurate, then it should be something more like

while(engineActive)
{
auto curr = Clock.currTime();

if(curr > finalTime)
break;

Thread.sleep(dur!"seconds(min(1, (finalTime - 
currTime).total!"seconds"())));
}

Incidentally, this use case shows that I should probably add overloads for 
some of the basic math functions for Duration... In any case, such an 
implementation would make it so that it doesn't sleep for longer than it needs 
to.

The other potential issue is responsiveness. If you want the loop to exit 
quickly after engineActive has been set to true, then you should probably be 
setting sleep to something more like 100ms (though if you set the value too 
low, then the loop wakes up more often than might be desirable, so it's a bit 
of a balancing act).

Regardless, the only potential issues lie with how quickly you want the loop 
to exit after the exit condition has been reached.

- Jonathan M Davis
June 03, 2011
Re: Is this a good way of setting up a timer?
I didn't even think about issue #1. Thanks again!
June 04, 2011
Re: Is this a good way of setting up a timer?
Hey, so is there a reason I'm not allowed to use immutable here:

immutable finalTime = Clock.currTime + dur!"seconds"(5);

Error: cannot implicitly convert expression
(currTime(cast(immutable(TimeZone))opCall()).opBinary(dur(5L))) of
type SysTime to immutable(SysTime)
June 05, 2011
Re: Is this a good way of setting up a timer?
On 2011-06-04 11:14, Andrej Mitrovic wrote:
> Hey, so is there a reason I'm not allowed to use immutable here:
> 
> immutable finalTime = Clock.currTime + dur!"seconds"(5);
> 
> Error: cannot implicitly convert expression
> (currTime(cast(immutable(TimeZone))opCall()).opBinary(dur(5L))) of
> type SysTime to immutable(SysTime)

Because SysTime does not currently work with immutable. There are multiple 
compiler bugs which prevent it (including the fact that you can't use postblit 
with non-mutable objects). It _should_ work, but it doesn't. Once the compiler 
does a better job dealing with const and immutable (which I believe is on the 
todo list after fixing destruction for temporaries), then it should work, but 
for now, it doesn't.

- Jonathan M Davis
June 06, 2011
Re: Is this a good way of setting up a timer?
On Fri, 03 Jun 2011 17:37:40 -0400, Andrej Mitrovic  
<andrej.mitrovich@gmail.com> wrote:

> On 6/3/11, Jonathan M Davis <jmdavisProg@gmx.com> wrote:
>>
>> Generally, you'd just put it to sleep for the period of time that you  
>> want
>> to
>> wait for. The only reason that I see to keep waking it up is if it  
>> could be
>> interrupted and effectively told to wake up - in which case you would be
>> sleeping and waking up over and over again, checking to see if enough  
>> time
>> had
>> passed or if you had been signaled to stop waiting.
>
> Yeah, I should have made a better example. Basically I have a loop
> that ends either after a specific time period, or it could end by
> receiving a signal. I just use a shared book for that, this would be
> it:
>
>     while (engineActive)  // shared bool
>     {
>         if (Clock.currTime > finalTime)
>             break;
>
>         Thread.sleep(dur!("seconds")(1));
>     }
>

I'm going to put on my old-school concurrency hat here :)

How I would write this is with a mutex and a condition.  Then instead of  
sleeping, I'd wait for the conditional.  I.e.:

while(engineActive) // shared bool
{
   auto curtime = Clock.currTime;
   if(curtime > finalTime)
      break;
   synchronized(mutex) cond.wait(finalTime - curTime);
}

Then, you have a function that sets the bool and signals the condition:

void endProgram()
{
   synchronized(mutex)
   {
      if(engineActive)
      {
          engineActive = false;
          cond.notifyAll();
      }
   }
}

Taking my hat off, I think the better way to do this is with  
std.concurrency.  But I have zero experience with it.  I'd guess there are  
ways to wait on your message queue, and some way to broadcast a message to  
all threads.

In any case, sleeping for a set period of time, and then checking a  
boolean works, but is both inefficient and less responsive than waiting  
for the exact condition you are looking for.

Trouble is, in some cases, a thread is waiting for *multiple* conditions,  
like input from a stream or exiting the program.  On some oses, it's very  
difficult to wait for both of those.  There are ways to solve this with  
helper threads, but this can also be wasteful.  Without further details on  
what your thread is doing, I can't say whether this would be a problem for  
you.

What I've done in the past is wait for the condition that needs to be more  
responsive (i.e. handling I/O) and use a timeout that allows a reasonable  
response to the other condition.

-Steve
June 06, 2011
Re: Is this a good way of setting up a timer?
On 6/6/11, Steven Schveighoffer <schveiguy@yahoo.com> wrote:
> Then, you have a function that sets the bool and signals the condition:
>
> void endProgram()
> {
>     synchronized(mutex)
>     {
>        if(engineActive)
>        {
>            engineActive = false;
>            cond.notifyAll();
>        }
>     }
> }

Interesting, thanks. There's some WinAPI functions like
WaitForMultipleObjects, I've read about them too.

Other than that, the while loop will go away and be replaced with some
kind of front-end for the user (e.g. GUI), while the background thread
crunches some numbers. The background thread should be able to signal
if something went wrong. Throwing exceptions from the work thread is
off limits, because they don't propagate to the foreground thread, so
I'm left with either using some kind of global boolean or I'd use
std.concurrency.send() to signal that something went wrong.
June 08, 2011
Re: Is this a good way of setting up a timer?
On 2011-06-03 15:02, Jonathan M Davis wrote:
> Incidentally, this use case shows that I should probably add overloads for
> some of the basic math functions for Duration...

I'm an idiot. I was thinking that min and max were in std.math and specific to 
built-in types, but we were smarter than that. They're defined as templated 
functions in std.algorithm and already work with core.time.Duration.

- Jonathan M Davis
Top | Discussion index | About this forum | D home