1

This is my code using QueryPeformanceCounter as timer.

//timer.h
class timer {
private:
    ...
public:
    ...
    double get(); //returns elapsed time in seconds
    void start();
};

//a.cpp
void loop() {
    timer t;
    double tick;
    double diff; //surplus seconds
    t.start();
    while( running ) {
        tick = t.get();
        if( tick >= 1.0 - diff ) {
            t.start();
            //things that should be run exactly every second
            ...
        }
        Sleep( 880 );
    }
}

Without Sleep this loop would go on indefinitely calling t.get() every time which causes high CPU usage. For that reason, I make it sleep for about 880 milliseconds so that it wouldn't call t.get() while not necessary.

As I said above, I'm currently using Sleep to do the trick, but what I'm worried about is the accuracy of Sleep. I've read somewhere that the actual milliseconds the program pauses may vary - 20 to 50 ms - the reason I set the parameter to 880. I want to reduce the CPU usage as much as possible; I want to, if possible, pause more than 990 milliseconds EDIT: and yet less than 1000 milliseconds between every loop. What would be the best way to go?

hjjg200
  • 335
  • 2
  • 11
  • The best way to go would be to quit relying on precise timings in Windows. It wasn't really designed with that in mind. Even with a tight loop and no sleeping at all, there's nothing to prevent Windows from switching to a different task just as you get to the 1 second mark. – Mark Ransom Oct 14 '16 at 15:26
  • Possible duplicate of [How to use SetTimer API](http://stackoverflow.com/questions/15685095/how-to-use-settimer-api) – user3528438 Oct 14 '16 at 15:27
  • It is not a good strategy, you never want to give the OS a good reason to *stop* running your code. You want to give it a good reason to *start* it. Which you can do by making Sleep() accurate, call timeBeginPeriod(). Give it more good reasons by calling SetThreadPriority(). timeSetEvent() is a good way to get a pretty consistent timer that can adjust for latency, beware it is asynchronous. You'll never get it more accurate than 1 msec and you can never assume it will *always* be 1 msec. The kernel and its device drivers will always come first. – Hans Passant Oct 14 '16 at 16:30

2 Answers2

0

I don't get why you are calling t.start() twice (it resets the clock?), but I would like to propose a kind of solution for the Sleep inaccuracy. Let's take a look at the content of while( running ) loop and follow the algorithm:

double future, remaining, sleep_precision = 0.05;
while (running) {
    future = t.get() + 1.0;

    things_that_should_be_run_exactly_every_second();

    // the loop in case of spurious wakeup
    for (;;) {
        remaining = future - t.get();
        if (remaining < sleep_precision) break;
        Sleep(remaining);
    }

    // next, do the spin-lock for at most sleep_precision
    while (t.get() < future);
}

The value of sleep_precision should be set empirically - OSes I know can't give you that.

Next, there are some alternatives of the sleeping mechanism that may better suit your needs - Is there an alternative for sleep() in C?

kamarkiewicz
  • 116
  • 1
  • 4
-1

If you want to pause more than 990 milliseconds, write a sleep for 991 milliseconds. Your thread is guaranteed to be asleep for at least that long. It won't be less, but it could be multiples of 20-50ms more (depending on the resolution of your OS's time slicing, and on the the cost of context switching).

However, this will not give you something running "exactly every second". There is just no way to achieve that on a time-shared operating system. You'll have to program closer to the metal, or rely on an interrupt from a PPS source and just pray your OS lets you run your entire loop iteration in one shot. Or, I suppose, write something to run in kernel mode…?

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • Is there a way to get resolution of my OS's time slicing? If it's guaranteed that `Sleep` won't exceed certain milliseconds, based on the resolution, it's good enough for me. – hjjg200 Oct 14 '16 at 15:45
  • 1
    @hʌn: You don't even know how many time slices it'll take. You cannot rely on a precise timing in such an operating system's user space, ever. The OS chooses when to run code! It could opt not to give control back to your process for 2 hours and be compliant to all relevant standards! Typically, instead of trying to run code exactly every second, we run code _as close to every second as we can get_, and make sure we adjust our variables according to how much time _actually_ passed. See also: variable frame rates in gaming – Lightness Races in Orbit Oct 14 '16 at 15:53
  • Please do read the documentation. `Sleep` can return early. Sorry, -1 for the misinformation. – IInspectable Oct 14 '16 at 20:26
  • @IInspectable: mmm my mistake, inaccurately porting POSIX knowledge there. By all means provide an edit. Or your own answer. Would you at least agree with the actual point of my answer, that the OP's approach is wrong and you won't get precise "scheduling" in this manner? – Lightness Races in Orbit Oct 15 '16 at 01:37