Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a C++ Non-Blocking Timer in Windows

On Linux, I would create a child process using fork() that will be my count-down timer, and once the timer ends, the child process will send a signal to the parent process to tell it that the timer has ended. The parent process then should handle the signal accordingly.

I have no idea how to do this on windows. Some people here recommended using threads but they never wrote any example code showing how to do that.

The most important thing is that the timer is non-blocking, meaning that it remains counting down in the background, while the program is accepting input from the user and handling it normally.

Could you please show me how?

Edit:

The application is a console one. And please show me example code. Thanks!

Update:

So after I read some of the suggestions here, I searched for some answers here and found this one which was helpful.

I then wrote the below code, which works, but not as it's supposed to be:

#include <Windows.h>
#include <iostream>
#include <string>
using namespace std;

#define TIMER_VALUE (5 * 1000) //5 seconds = 5000 milli seconds
HANDLE g_hExitEvent = NULL;

bool doneInTime = false;
string name;

bool inputWords();


//The below function will be called when the timer ends
void CALLBACK doWhenTimerEnds(PVOID lpParameter, BOOLEAN TimerOrWaitFired)
{
    if(!doneInTime)
    {
        cout << "\nOut of time ... try again ..." << endl;
        name = "";
        doneInTime = inputWords();
    }
    SetEvent(g_hExitEvent);
}


bool inputWords()
{

    /* doWhenTimerEnds() will be called after time set by 5-th parameter and repeat every 6-th parameter. After time elapses,
    callback is called, executes some processing and sets event to allow exit */
    HANDLE hNewTimer = NULL; 
    BOOL IsCreated = CreateTimerQueueTimer(&hNewTimer, NULL, doWhenTimerEnds, NULL, TIMER_VALUE, 0, WT_EXECUTELONGFUNCTION);

    g_hExitEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

    cout << "Input your name in 5 seconds .. " << endl;
    std::getline(cin, name);

    DeleteTimerQueueTimer(NULL, hNewTimer, NULL);
    return true;
}

int main()
{
    doneInTime = inputWords();
    cout << "Hello, " << name << "! You're done in time" << endl;

    //WaitForSingleObject(g_hExitEvent, 15000);

    system("pause");
    return 0;
}

The problem is, the interrupted getline() never stops, and the subsequent getline()'s read even the text previously entered! how can I fix that please? And if there's a better way of doing it, could you please point me out to it?

like image 439
Ahmed Fakhry Avatar asked Jul 04 '26 12:07

Ahmed Fakhry


1 Answers

Here's an example that works with the Windows API:

#include <windows.h>
#include <iostream>

DWORD WINAPI threadProc()
{
    for (int i = 0; ; ++i)
    {
        std::cout << i << '\n';
        Sleep (1000);
    }

    return 0;
}

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, 
                    LPSTR lpszCmdLine, int iCmdShow)
{
    CreateThread (NULL, 0, (LPTHREAD_START_ROUTINE)threadProc, NULL, 0, NULL);

    int i;
    std::cin >> i;

    return ERROR_SUCCESS;
}

Basically the main function creates a thread that executes using the procedure threadProc. You can think of threadProc as the thread. Once it ends, the thread ends.

threadProc just outputs a running count every second or so, while the main function waits for a blocking input. Once an input is given, the whole thing ends.

Also be aware that CreateThread was used with minimal arguments. It returns a handle to the thread that you can use in functions like WaitForSingleObject, and the last argument can receive the thread id.

like image 91
chris Avatar answered Jul 06 '26 02:07

chris



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!