C++中类似于window.setTimeout()的函数

10
在JavaScript中有一个非常好用的函数window.setTimeout( func, 1000 ) ;,它会在1000毫秒后异步地执行func
我想在C++中实现类似的功能(不使用多线程),于是写了一个示例循环:
    #include <stdio.h>
struct Callback { // 要执行该函数的时间。 double execTime ;
// 在execTime过后要执行的函数。 void* func ; } ;
// 用于记录程序整体时间的全局变量。 double time ;
// 待执行的示例函数 void go() { puts( "GO" ) ; }
int main() { // 开始计时 time = 0 ;
// 创建一个示例回调 Callback c1 ; c1.execTime = 10000 ; c1.func = go ;
while( 1 ) { // 如果已经到达该执行时间,则执行相应的函数 if( time > c1.execTime ) { c1.func ; // !! doesn't work! }
time++; } }
那么如何让这个程序能够正确执行呢?

你是否正在寻找sleep()函数? - just_wes
不是真的。我希望程序继续运行并稍后再调用它们。 - bobobobo
它真的不应该依赖于平台。 - bobobobo
3
问题实际上是关于加粗的那一行,c1.func并没有调用这个函数,它似乎什么也没做! - bobobobo
回想起现在,天哪,当时的我太菜了。括号,括号! - bobobobo
5个回答

14

在C++11发布后,如果您正在使用支持C++11的编译器,则可以轻松地使用lambda可变参数模板函数异步线程来模拟JavaScript函数。

这是我为setTimeout编写的代码,已经完全测试过:

setTimeout函数的定义:

    #include <windows.h>//different header file in linux
    #include <future>
    using namespace std;

    template <typename... ParamTypes>
    void setTimeOut(int milliseconds,std::function<void(ParamTypes...)> func,ParamTypes... parames)
    {   
        std::async(std::launch::async,[=]()
        {       
            Sleep(milliseconds);
            func(parames...); 
        });
     };

这个函数使用c+11的可变模板参数接收可变数量的参数,以下代码可以展示如何使用它:

    #include <iostream>
    #include <thread>
    #include <string>
    #include <functional>
    #include <windows.h>

    #include <future>
    using namespace std;
    int main() 
    {
        std::mutex locker;
        std::function<void()> func1 = [&]()
        {
            std::unique_lock<std::mutex> lk(locker);
            std::cout << "func 1 is trigged:" << "   no parameter" << std::endl;
            lk.unlock();
        };      
        std::function<void(int)> func2 = [&](int param)
        {
            std::unique_lock<std::mutex> lk(locker);
            std::cout << "func 2 is trigged:" << "   int: " << param <<std::endl;
            lk.unlock();
        };
        std::function<void(int,std::string)> func3 = [&](int param1,std::string param2)
        {
            std::unique_lock<std::mutex> lk(locker);
            std::cout << "func 3 is trigged:" << "   int: " << param1 << ";  string: " << param2 << std::endl;
            lk.unlock();
        };

        for(int index=0;index<100;index++)
        {
            std::unique_lock<std::mutex> lk1(locker);
            std::cout << "set timer for func  1" << std::endl;
            lk1.unlock();
            setTimeOut<>(1000,func1);

            std::unique_lock<std::mutex> lk2(locker);
            std::cout << "set timer for func  2" << std::endl;
            lk2.unlock();
            setTimeOut<int>(2000,func2,10000);

            std::unique_lock<std::mutex> lk3(locker);
            std::cout << "set timer for func  3" << std::endl;
            lk3.unlock();
            setTimeOut<int,std::string>(5000,func3,10000,"ddddd");
        }
        Sleep(10000000);
    }

3
建议按照这里的描述使用 threadchrono 进行睡眠操作:https://dev59.com/-2855IYBdhLWcg3wuGwM#10613664 - Max Strater
如何将成员函数或静态函数发送给 setTimeOut 而不是 std::function? - Ambroise Rabier

5

将类型为void (*)()Callback::func函数指针创建,即:

struct Callback
{
    double execTime;
    void (*func)();
};

您可以这样调用该函数:
c1.func();

此外,不要忙等待。在Linux上使用{{link1:ualarm}},在Windows上使用{{link2:CreateWaitableTimer}}。

1

我只是在修复你的代码,而不是超越思考。其他答案已经给出了一些指针。

为了更好的类型安全性,你应该按照以下方式声明回调指针:

  // The function to execute after execTime has passed
  void (*func)() ;

然后,将其调用为:

  c1.func() ;

或者您可以使用(* c1.func)()。我通常在函数指针中使用这种语法。此外,我认为“c1.func =&go”更清晰易读。 - Mr.Ree

1

在C ++本身中,你的功能相当受限。你需要一个多线程的操作系统,在其中可以使用sleep函数(您仍然可以使用单独的线程使程序继续运行),或者需要一个消息传递系统,例如Windows。

我看到的唯一其他方法是在代码中散布大量调用调用返回true或false的函数,具体取决于时间是否已经过去。该函数当然可以是回调,但您仍然需要定期调用它。


是的!这就是我想要做的。 - bobobobo

0
另一个(更好的)答案是在C++中使用头文件,并像这样声明函数:
#include <functional>

function<void ()> func ;

// assign like
func = go ; //go is a function name that accepts 0 parameters
// and has return type void

// exec like
func() ;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接