2

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?

Community
  • 1
  • 1
Ahmed Fakhry
  • 139
  • 1
  • 4
  • 12
  • Important question: Is your application a console application, or a GUI application? The answers will be very different. – Greg Hewgill May 27 '12 at 22:27
  • C++11 has `std::thread`, and the winapi has `CreateThread`. Either of those should be relatively easy to find examples on. – chris May 27 '12 at 22:27
  • 4
    That was a bad approach under Linux, and you're getting bad recommendations here. What tasks, besides waiting for console input, are you doing during the countdown? Does the countdown need to interrupt a task, or will the tasks poll to see if the countdown has elapsed, or...? – Ben Voigt May 27 '12 at 22:45
  • Just to ask the user to input something within a specific time, if the time allowed elapses, then the program will stop taking input from the user and asks him whether to restart or do something else.. – Ahmed Fakhry May 28 '12 at 00:11

5 Answers5

6

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.

chris
  • 60,560
  • 13
  • 143
  • 205
  • Ok, Thanks your code is almost working. I just had to change `int WINAPI WinMain (HINST...` to `int main()` to be able to run it. The timer is counting and printing output without blocking main which is waiting for input at the `cin`. Now I need to make communications between the thread and main, once the counter reaches 0 for example, send a signal or something to main to stop reading input from user, and redirect the program somewhere else. Thanks – Ahmed Fakhry May 28 '12 at 01:44
  • @AhmedFakhry, first of all, that's the official signature for a Windows application entry point. I suspect you don't have a Windows GUI project. With a blocking process like input, you might be better to put the input in another thread, and then terminate that thread when you wish. That's the only real way I can think of from there to stop it in the middle of input. That said, you could probably do this much more easily with something like `SetTimer` with your own callback. Specify the time, and it calls your function once the timer expires. See gahcep's answer for that approach. – chris May 28 '12 at 01:59
  • could you please see my updated question, and see if you can help? – Ahmed Fakhry May 29 '12 at 21:36
5

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.

Sergei Danielian
  • 4,938
  • 4
  • 36
  • 58
1

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.

0

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.

therealdm
  • 91
  • 1
  • 6
-2

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++;
}

}