在Windows中创建C ++非阻塞计时器

时间:2012-05-27 22:26:01

标签: c++ windows winapi visual-c++

在Linux上,我将使用fork()创建一个子进程,它将是我的倒计时器,一旦计时器结束,子进程将向父进程发送一个信号告诉它计时器已经结束。然后父进程应该相应地处理信号。

我不知道如何在Windows上执行此操作。这里的一些人建议使用线程,但他们从未编写任何示例代码来说明如何执行此操作。

最重要的是计时器是非阻塞的,这意味着它在后台继续倒计时,而程序正在接受用户的输入并正常处理。

你能告诉我怎么样吗?

修改

该应用程序是一个控制台。请告诉我示例代码。谢谢!

更新

所以在我阅读了一些建议之后,我在这里搜索了一些答案并找到了这个one,这很有帮助。

然后我编写了下面的代码,它起作用,但并不像它应该的那样:

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

问题是,中断的getline()永远不会停止,后续的getline()甚至会读取之前输入的文本!我该怎么办呢?如果有更好的方法,请你指点一下吗?

5 个答案:

答案 0 :(得分:5)

以下是适用于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;
}

主要功能基本上创建一个使用过程threadProc执行的线程。您可以将threadProc视为主题。一旦结束,线程结束。

threadProc每秒输出一次运行计数,而main函数则等待阻塞输入。一旦给出输入,整个事情就会结束。

另请注意CreateThread使用最少的参数。它返回一个可以在WaitForSingleObject之类的函数中使用的线程的句柄,最后一个参数可以接收线程id。

答案 1 :(得分:4)

您可以在线程内外使用Waitable Timer Objects。要使用此类对象,只需使用SetWaitableTimer函数。根据MSDN的功能定义:

  

激活指定的等待计时器。当到期时间到来时,定时器被发出信号,并且设置定时器的线程调用可选的完成例程。

答案 2 :(得分:1)

如果你为它们实现kbhit()函数,这是另一个跨平台工作的解决方案:

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

这种方法使用boost :: thread,并在创建线程后等待5秒钟来设置expiration标志,然后再次等待线程,直到它完成其功能。

答案 3 :(得分:0)

寻找同一问题的解决方案,我发现这篇文章非常有用:

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

正如您似乎已经想到的那样,最好的答案(在Windows 2000之后的世界中)似乎是队列计时器,而不是CreateTimerQueueTimer

答案 4 :(得分:-2)

试试这个:

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

}