Sleep problem in Windows!

Hi there, I'm new here!
I hope you can help me with this :)

Well, im programming a text bassed game in C++ and I have the following issue:
Between every text i have a dormir(time in ms) function which basically do this:
It Sleeps while i is minor than x and it's not pressed any key.

But I dont know why, this takes a long, i mean:

dormir(1000) should be 1 second
but it spends more time sleeping (Sometimes, it is not something stable)

1
2
3
4
5
6
7
void Personaje::dormir(int x){
    int i = 0;
    do{
    	i++; 
	Sleep(1); //1ms
    }while(i<x && !kbhit()); //Stop sleeping when i reach x and !kbh
}


I dont know if there is another solution for this or another way to program this, i've researched a lot and this is the only way i think you can "stop" a sleep.

Sorry for my bad english and thank you all :)
Last edited on
In my experience, if you set dwMilliseconds to a value greater than 0 but less than one tick (e.g. Sleep(1);), the thread will sleep for at least one tick. So if one tick is 1/64 second (15.625ms), and you Sleep(1);, your thread will (in my experience) sleep for at least 15.625ms. On a server with Windows Server 2003 Enterprise x64 Edition, 1000 Sleep(1); calls take 15.625 seconds (exactly 1000 ticks). 1000 Sleep(15) calls on the same server takes 15.625 seconds as well.

Source: https://msdn.microsoft.com/en-us/library/windows/desktop/ms686298(v=vs.85).aspx
If it would take always the same time, it would be great for me, but the inestability is the thing that is disturbing me...

Sometimes it takes dormir(1000) around a second and other times like 5 or 6 seconds... that is killing me

How can i do a timer which stops when keyboardhit or reaches the time sent by parameter without this problem?

Thanks for your patience :)
Last edited on
Here dormir_1() is your function, and dormir_2() is a modified function which can handle whole seconds.

Ouput on my PC

Test_1 : 1 secs
time taken = 1.953 secs

Test_2 : 1 secs
time taken = 1.000 secs

Test_1 : 2 secs
time taken = 3.906 secs

Test_2 : 2 secs
time taken = 2.000 secs

Test_1 : 3 secs
time taken = 5.922 secs

Test_2 : 3 secs
time taken = 3.000 secs


The use of Sleep() and kbhit() (or _kbhit()) says you're working with Windows; this isn't a generic solution.

While you can't stop a Sleep() call, you could use WaitForSingleObject() to wait on a keyboard input with a timeout value. But this would require more involved code.

Andy

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <iostream>
#include <iomanip>
#include <ctime>
#include <conio.h>

void dormir_1(int timeInMsecs) {
    int i = 0;
    do {
        i++; 
        Sleep(1); //1ms
    } while(i<timeInMsecs && !kbhit()); //Stop sleeping when i reach x and !kbh
}

void dormir_2(int timeInSecs) { // now in secs
    clock_t delta = CLOCKS_PER_SEC * timeInSecs;
    clock_t now = clock();
    clock_t end = now + delta;
    do {
        Sleep(1); //1ms
        now = clock();
    } while((now < end) && !kbhit()); //Stop sleeping when now reach end and !kbh
}

void Test_1(int secs) {
    std::cout << "Test_1 : " << secs << " secs\n";

    clock_t start = clock();
    dormir_1(1000 * secs);
    clock_t stop = clock();

    double time_taken = (double)(stop - start)/CLOCKS_PER_SEC;
    std::cout << "time taken = " << time_taken << " secs\n";
    std::cout << "\n";
}

void Test_2(int secs) {
    std::cout << "Test_2 : " << secs << " secs\n";

    clock_t start = clock();
    dormir_2(secs);
    clock_t stop = clock();

    double time_taken = (double)(stop - start)/CLOCKS_PER_SEC;
    std::cout << "time taken = " << time_taken << " secs\n";
    std::cout << "\n";
}

int main() {
    std::cout << std::fixed << std::setprecision(3);

    for(int t = 1; t <= 3; ++t) {
        Test_1(t);
        Test_2(t);
    }

    return 0;
}
Last edited on
Wow Andy, that actually was super useful, now i will try to manage how ctime works, i barely used it to randomize.

Thank you so much, that was a huge help mate.
The thing is, why this happens?
The temporal cost of i++ isnt constant?

I'm just shocked, thank you so much Andy! :)
The temporal cost of i++ isnt constant?

No.

As m4ster r0shi pointed out, Sleep(1) doesn't sleep for just 1ms.

So you're waiting for 1000 * <something a bit longer than 1ms>. It's this something that's a bit variable, depending on what the PC is up to.

Andy
PS If you do just want to dormir for periods of the order of seconds, then you can probably Sleep a bit longer that "1 msec" each time. Maybe 10 or even 20 msec?
Last edited on
@Duoas

The code you point at doesn't run correctly as-is for me when I run it from Visual Studio. The iskeypressed() function returns immediately so the intended countdown does not run.

The problem is due to a pending FOCUS_EVENT on the console input queue. Using ReadConsoleInput to clear the queue (if not empty) at program startup fixes the problem.

The problem is not there when you run the program directly from a command prompt. But it is if you "start" the program.

Andy
Last edited on
Yes, that version of iskeypressed() returns if any input is waiting in the input queue. So the user program has to clear the input queue, either by using ReadConsoleInput() to drain the events or by using cin before calling iskeypressed().

Sorry, I did not expect it to be run by double-clicking.

(A more advanced version if iskeypressed() would also use PeekConsoleInput() to look ahead for any key presses.)
1
2
3
4
clock_t start = clock();
dormir_2(secs);
clock_t stop = clock();
double time_taken = (double)(stop - start)/CLOCKS_PER_SEC;

This measures processor time (instead of elapsed wall clock time).

In the posted code, it appears to give results very close to what was expected because there are no other threads in the process which use processor resources, and because the only running thread was never taken off the processor (there were no other threads in a ready state waiting for processor to become available.)
Topic archived. No new replies allowed.