How to Create Timer Events Using C++ 11

C++11 Timer Function?

the comment thomas posted it good so that's clearly the best link
Apart from it I have made an example that can help.

#include <iostream>
#include <stdio.h>
#include <thread>
using namespace std;
int main()
{
std::thread([]() {std::this_thread::sleep_for(std::chrono::milliseconds(1000));
cout<<"end of the thread\n";
}).detach();

for (int i=0;i<20;++i)
{
std::this_thread::sleep_for(std::chrono::milliseconds(100));
cout<<i<<std::endl;
}
return 0;
}

And my output is:
0
1
2
3
4
5
6
7
8
end of the thread
9
10
11
12
13
14
15
16
17
18
19

Hope that helps :-)

C++ 11: Calling a C++ function periodically

The problem in your code is that your lambda expression inside your "start" function captures the local variables by reference, using the [&] syntax. This means that the lambda captures the interval and func variables by reference, which are both local variables to the start() function, and thus, they disappear after returning from that function. But, after returning from that function, the lambda is still alive inside the detached thread. That's when you get the "bad-function-call" exception because it tries to call func by reference to an object that no longer exists.

What you need to do is capture the local variables by value, with the [=] syntax on the lambda, as so:

void start(int interval, std::function<void(void)> func)
{
_execute = true;
std::thread([=]()
{
while (_execute) {
func();
std::this_thread::sleep_for(
std::chrono::milliseconds(interval));
}
}).detach();
}

This works when I try it.

Or, you could also list out the values you want to capture more explicitly (which I generally recommend for lambdas):

void start(int interval, std::function<void(void)> func)
{
_execute = true;
std::thread([this, interval, func]()
{
while (_execute) {
func();
std::this_thread::sleep_for(
std::chrono::milliseconds(interval));
}
}).detach();
}

EDIT

As others have pointed out, the use of a detached thread is not a great solution because you could easily forget to stop the thread and you have no way to check if it's already running. Also, you should probably make the _execute flag atomic, just to be sure it doesn't get optimized out and that the reads / writes are thread-safe. You could do this instead:

class CallBackTimer
{
public:
CallBackTimer()
:_execute(false)
{}

~CallBackTimer() {
if( _execute.load(std::memory_order_acquire) ) {
stop();
};
}

void stop()
{
_execute.store(false, std::memory_order_release);
if( _thd.joinable() )
_thd.join();
}

void start(int interval, std::function<void(void)> func)
{
if( _execute.load(std::memory_order_acquire) ) {
stop();
};
_execute.store(true, std::memory_order_release);
_thd = std::thread([this, interval, func]()
{
while (_execute.load(std::memory_order_acquire)) {
func();
std::this_thread::sleep_for(
std::chrono::milliseconds(interval));
}
});
}

bool is_running() const noexcept {
return ( _execute.load(std::memory_order_acquire) &&
_thd.joinable() );
}

private:
std::atomic<bool> _execute;
std::thread _thd;
};

How to time event in C++?

The <chrono> library in standard C++ provides the best way to do this. This library provides a standard, type safe, generic API for clocks.

#include <chrono>
#include <iostream>

int main() {
using std::chrono::duration_cast;
using std::chrono::nanoseconds;
typedef std::chrono::high_resolution_clock clock;

auto start = clock::now();
// stuff
auto end = clock::now();
std::cout << duration_cast<nanoseconds>(end-start).count() << "ns\n";
}

The actual resolution of the clock will vary between implementations, but this code will always show results in nanoseconds, as accurately as possible given the implementation's tick period.

Can you implement a timer without a sleep in it using standard c++/c++11 only?

C++11 provides us with std::condition_variable. In your timer you can wait until your condition has been met:

// Somewhere else, e.g. in a header:
std::mutex mutex;
bool condition_to_be_met{false};
std::condition_variable cv;

// In your timer:
// ...
std::unique_lock<std::mutex> lock{mutex};
if(!cv.wait_for(lock, std::chrono::milliseconds{timeout_ms}, [this]{return condition_to_be_met;}))
std::cout << "timed out!" << std::endl;

You can find more information here: https://en.cppreference.com/w/cpp/thread/condition_variable

To signal that the condition has been met do this in another thread:

{
std::lock_guard<std::mutex> lock{mutex}; // Same instance as above!
condition_to_be_met = true;
}
cv.notify_one();

How to use timer in C?

You can use a time_t struct and clock() function from time.h.

Store the start time in a time_t struct by using clock() and check the elapsed time by comparing the difference between stored time and current time.



Related Topics



Leave a reply



Submit