简体   繁体   English

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

[英]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. 在Linux上,我将使用fork()创建一个子进程,该进程将成为我的倒数计时器,并且一旦计时器结束,该子进程将向父进程发送一个信号,告知其计时器已结束。 The parent process then should handle the signal accordingly. 然后,父进程应相应地处理信号。

I have no idea how to do this on windows. 我不知道如何在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! 问题是,中断的getline()永远不会停止,而后续的getline()甚至会读取先前输入的文本! 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: 这是与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 . 基本上,main函数创建一个使用threadProc过程执行的线程。 You can think of threadProc as the thread. 您可以将threadProc视为线程。 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. threadProc输出一次运行计数,而main函数则等待阻塞输入。 Once an input is given, the whole thing ends. 一旦输入,整个过程就结束了。

Also be aware that CreateThread was used with minimal arguments. 另请注意, CreateThread与最少的参数一起使用。 It returns a handle to the thread that you can use in functions like WaitForSingleObject , and the last argument can receive the thread id. 它返回线程的句柄,您可以在诸如WaitForSingleObject函数中使用该句柄,最后一个参数可以接收线程ID。

You can use a Waitable Timer Objects either in or outside a thread. 您可以在线程内或线程外使用等待计时器对象 To use such kind of object just use SetWaitableTimer function. 要使用这种对象,只需使用SetWaitableTimer函数。 The function definition according to MSDN: 根据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: 这是另一个解决方案,如果您为它们实现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;
}

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. 这种方法使用boost :: thread,并在创建线程后等待5秒钟以设置到期标志,然后再次等待线程,直到完成其功能为止。

Looking for a solution to the same problem, I found this article very helpful: 在寻找相同问题的解决方案时,我发现本文非常有帮助:

http://www.codeproject.com/Articles/1236/Timers-Tutorial 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 . 如您所知,最好的答案(在Windows 2000后的世界中)似乎是Queue Timers, 例如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++;
}

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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