In javascript there's this sweet, sweet function window.setTimeout( func, 1000 ) ;
which will asynchronously invoke func
after 1000 ms.
I want to do something similar in C++ (without multithreading), so I put together a sample loop like:
#include <stdio.h>
struct Callback
{
// The _time_ this function will be executed.
double execTime ;
// The function to execute after execTime has passed
void* func ;
} ;
// Sample function to execute
void go()
{
puts( "GO" ) ;
}
// Global program-wide sense of time
double time ;
int main()
{
// start the timer
time = 0 ;
// Make a sample callback
Callback c1 ;
c1.execTime = 10000 ;
c1.func = go ;
while( 1 )
{
// its time to execute it
if( time > c1.execTime )
{
c1.func ; // !! doesn't work!
}
time++;
}
}
How can I make something like this work?
Make Callback::func
of type void (*)()
, i.e.
struct Callback
{
double execTime;
void (*func)();
};
You can call the function this way:
c1.func();
Also, don't busy-wait. Use ualarm
on Linux or CreateWaitableTimer
on Windows.
After C++11 came out, and if your are using c++11 supported compiler, you can use lambda, variadic template function and asynchronous thread to simulate javascript function in c++ easily.
Here is the code I wrote for setTimeOut, it is fully tested:
setTimeOut funtion's definition:
#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...);
});
};
This function accepts variable arguments by using c+11's variadic template,
The code can show you how to use it:
#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);
}
In C++ by itself, you're pretty limited. You need either a multithreaded OS, where you could use a sleep function (you can still have the program continue running with a separate thread), or you need a messaging system, like Windows.
The only other way I see that you can do something is to have a lot of calls scattered throughout the code that calls a function that returns true or false, depending on whether the time has elapsed. The function could, of course, be a callback, but you would still need to call it periodically.
I'm only fixing your code here, not thinking outside the box. The other answers already gave some pointers for that.
For better type safety, you should declare your callback pointer as follows:
// The function to execute after execTime has passed
void (*func)() ;
Then, call it as:
c1.func() ;
Another (better) answer would be to use the <functional>
header in C++, and declare the function like so:
#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() ;