2
\$\begingroup\$

I've tried to write a simple timer class that could later be used in games, such as for updating the screen every second. Problem is, I read gettimeofday() was UNIX-specific and unsafe to use as well (that last one I'm not sure about). I know C has a clock() function, but it only has second precision.

Is there a way to get time in a cross-platform way that has millisecond precision at the very least? I know Boost and other libraries exist, but I prefer not to use them for various reasons.

class Timer
{
private:
   bool m_isRunning;
   int m_startTime;
   int m_delayAmount;
   double m_initialDelay;

public:
   Timer(int delayAmount, double initialDelay = 0.0)
   {
      m_delayAmount = delayAmount * 1000; 
      m_initialDelay = initialDelay/1000;
   }

   void start()
   {
      m_startTime = getMilliseconds();
      clock_t endwait = clock() + m_initialDelay * CLOCKS_PER_SEC;
      while (clock() < endwait);
      m_isRunning = true;
   }

   void stop()
   {
      m_isRunning = false;
   }

   bool isRunning()
   {
      return m_isRunning;
   }

   bool hasTicked()
   {
      if (getMilliseconds() - m_startTime > m_delayAmount)
      {
         m_startTime = getMilliseconds();
         return true;
      }
      else
      {
         return false;
      }

   }

   int getMilliseconds() const
   {
      timeval t;
      gettimeofday(&t, NULL);
      return (t.tv_sec * 1000000) + t.tv_usec;
   }
};

This is kinda how you would use it. The program just prints a message every second after an initial delay of 3 seconds.

int main (int argc, char * const argv[]) 
{
   Timer timer(1000, 3000);
   timer.start();
   int i = 1;
   while (timer.isRunning())
   {
      if (timer.hasTicked())
      {
         cout << "tick " << i++ << endl;
      }
   }
}
\$\endgroup\$
1
  • \$\begingroup\$ Busy waits are not a good idea. while (clock() < endwait);. It will basically burn your CPU out as it goes to 100% utilization in a tight loop. Your timer may work for this scenario but overall not that useful. I would expect it to take an initial delay, a recurring delay and function. Then the function is automatically called each time the time out period is reached. Here you have to actually check to see to see if the timer has gone off. \$\endgroup\$ Commented Mar 8, 2012 at 21:40

3 Answers 3

4
\$\begingroup\$

I think you should take a look at std::chrono and std::thread.

If you want to replicate, say, a VB timer or whatever (something that calls a function every second), you can do this:

template<typename Func>
void timer(Func func, unsigned interval)
{
    while(true)
    {
        std::this_thread

        std::this_thread::sleep_for(;
            std::chrono::milliseconds(interval));   
        func();
    }
}

Of course, you can change that into a functor and give it a bool for start and stop.

if you just want to measure the elapsed time then just use chrono

std::chrono::system_clock::time_point start=std::chrono::system_clock::now();    
//start timer 
//do stuff
std::chrono::duration<double> time_taken=std::chrono::system_clock::now() - start;

Don't reinvent the wheel. If you don't have access to C++11, then all of this functionality can be used from Boost.

\$\endgroup\$
1
\$\begingroup\$

It is not clear why one is multiplied by 1000 and the other divided by a thousand (nor why one is an integer and the other a double).

  m_delayAmount = delayAmount * 1000; 
  m_initialDelay = initialDelay/1000;

This just detects if the delay has been exceeded:

  if (getMilliseconds() - m_startTime > m_delayAmount)

Not that we have gone twice since it happened (that may be useful to know). Also if you fail to call it for 5 minutes the next one is still 3 seconds away. I would like the ability to to call my function for each alarm it had missed or if this delay was 4.5 seconds then I wan the next one to be 1.5 seconds away (rather than 3).

Should this not be private?

int getMilliseconds() const

It does not seem this needs to be part of the interface.

\$\endgroup\$
1
\$\begingroup\$

The clock() function in C standard library measures the approximation of the spent CPU time of the process - it does not count real wall-clock time. As such don't use it for timing.

On Unix-based systems(or any system conforming to SUSv2 and POSIX.1-2001 standards), please take a look at clock_gettime() and CLOCK_MONOTONIC - both found in time.h. The Unix manpage for covers the function quite well. :)

On Unix-based machines you might want to set an interval timer by using the setitimer() function from sys/time.h to return a signal to the process which you then handle accordingly. Again, the Unix manpages are the most precise, easily accessible source of information on the matter.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.