3

I am writing a thread library, and when scheduling the threads I need to know how long they've been ready. Every Thread instance has a timeval _timeInReady field, and when I push an instance to the ready queue I call this function:

void Thread::startTiming() {
    gettimeofday(&_timeInReady, NULL);
}

When I want to check the current _timeInReady value I call:

double Thread::getTimeInReady() const {
    return TIME(_timeInReady.tv_sec,_timeInReady.tv_usec);
}

Where TIME is #define TIME(a,b) ((a*1000000) + b) So that I get the total time in microseconds.

My problem is that for some reason, I get crazy negative values (such as -10293843) when I check that field after a while.

Any ideas? Thanks!

yotamoo
  • 5,334
  • 13
  • 49
  • 61
  • What, precisely, do you observe that makes you think that you have negative numbers? If it is a print statement, please show it. If it is a debugger inspection, please tell us more about that. – Robᵩ Apr 24 '12 at 15:56

3 Answers3

5

You should return the result as a 64-bit unsigned integer, as you want an integer microsecond result, not a fractional second (which would imply returning double):

unsigned long long Thread::getTimeInReady() const
{
    return (unsigned long long)_timeInReady.tv_sec * 1000000ULL +
        (unsigned long long)_timeInReady.tv_usec;
}

Your system might have uint64_t which is a more concise than unsigned long long, or you could typedef it.

trojanfoe
  • 120,358
  • 21
  • 212
  • 242
1

On my computer, all of tv_sec, tv_usec, and 1000000 are signed 32-bit quantities. Signed 32-bit values overflow when asked to hold a number bigger than 2^31 or so.

As a result, this expression:

((x.tv_sec*1000000) + x.tv_usec)

will overflow in 2^31 / 10^6 seconds, or about 2,147 seconds. As long as your program only deals in time intervals shorter than 35 minutes, you should be okay.

If you'd like to represent values >= 35 minutes, try replacing your #define with this:

#define TIME(a,b) ((a*1000000ull) + b)

Through the standard promotions, this change will cause all of your math to be performed with unsigned long long values.

You may, but need not, change your double to uint64_t. That's up to you.

Robᵩ
  • 163,533
  • 20
  • 239
  • 308
0

Try this for getting time for 32-bit systems :-

struct timeval time;
gettimeofday(&time, NULL);
unsigned long long secTime = ((unsigned long long)time.tv_sec) * 1000 + ((unsigned long long)(time.tv_usec))/1000;
Astha Garg
  • 1,022
  • 7
  • 21