简体   繁体   中英

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?

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.

You can use a Waitable Timer Objects either in or outside a thread. To use such kind of object just use SetWaitableTimer function. The function definition according to MSDN:

Activates the specified waitable timer. When the due time arrives, the timer is signaled and the thread that set the timer calls the optional completion routine.

Here is another solution which will work cross-platform if you implement the kbhit() function for them:

#include <boost/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>

#if defined(WIN32)
    #include <conio.h>
#else
    // kbhit() implementation for other platforms
#endif

boost::mutex    mutex_;
bool            timeExpired_ = false;

void threadFunc()
{
    while(1) {
        {
            boost::mutex::scoped_lock lock(mutex_);
            if (timeExpired_)
                break;
            #if defined(WIN32)
                kbhit();
            #endif
        }
        boost::this_thread::sleep(boost::posix_time::milliseconds(1));
    }
}

int main(int argc, char *argv[])
{
    boost::thread worker(threadFunc);

    worker.timed_join(boost::posix_time::milliseconds(5000));

    {
        boost::mutex::scoped_lock lock(mutex_);
        timeExpired_ = true;
    }

    worker.join();

    return 0;
}

This approach uses boost::thread and after creating the thread waits for 5 seconds to set the expiration flag and then waits for the thread again until it is done with its functionality.

Looking for a solution to the same problem, I found this article very helpful:

http://www.codeproject.com/Articles/1236/Timers-Tutorial

As you seem to have figured out, the best answer (in the post-Windows 2000 world) seems to be Queue Timers, à la CreateTimerQueueTimer .

try this one:

//Creating Digital Watch in C++
#include<iostream>
#include<Windows.h>
using namespace std;

struct time{

int hr,min,sec;
};
int main()
{
time a;
a.hr = 0;
a.min = 0;
a.sec = 0;

for(int i = 0; i<24; i++)
{
    if(a.hr == 23)
    {
        a.hr = 0;
    }

    for(int j = 0; j<60; j++)
    {
        if(a.min == 59)
        {
            a.min = 0;
        }

        for(int k = 0; k<60; k++)
        {
            if(a.sec == 59)
            {
                a.sec = 0;
            }

            cout<<a.hr<<" : "<<a.min<<" : "<<a.sec<<endl;
            a.sec++;
            Sleep(1000);
            system("Cls");
        }
    a.min++;

}

    a.hr++;
}

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM