Need to Call a Function at Periodic Time Intervals in C++

How to call a function at periodic interval that takes in an object as argument in C++?

operator() of non-mutable lambda is const.
As you capture by copy, you cannot then mutate your captured "member".

You probably want to capture by reference instead:

set_interval([&window] { foo(window); }, 1000ms, cancel);

or if you really want copy, make the lambda mutable:

set_interval([window] mutable { foo(window); }, 1000ms, cancel);

periodic timer intervals in C++

You can roll your own with a class that launches a thread to do the calls. Here's a simple one I use that will call every period until the class's destructor runs. You can tweak the details of the implementation to achieve most anything you want:

#include <atomic>
#include <chrono>
#include <functional>
#include <thread>

class call_every
{
std::function<void()> f_;
std::chrono::system_clock::duration d_;
std::chrono::system_clock::time_point run_now_;
std::atomic_bool quit_;
std::thread thr_;

public:
~call_every()
{
quit_ = true;
thr_.join();
}

template <class F>
explicit call_every(F f, std::chrono::system_clock::duration d)
: f_{std::move(f)}
, d_{d}
, run_now_{std::chrono::system_clock::now()}
, quit_{false}
, thr_{&call_every::run, this}
{}

private:
void run()
{
while (!quit_)
{
f_();
run_now_ += d_;
std::this_thread::sleep_until(run_now_);
}
}
};

#include <iostream>

int
main()
{
using namespace std;
using namespace std::chrono;
call_every x{[]{cout << "Hi" << endl;}, 5s};
this_thread::sleep_for(15s);
}

$ a.out
Hi
Hi
Hi
Hi
$

Here's a variant of the above that will be more responsive to the quit_ command. Instead of unconditionally sleeping for the duration, it uses a condition_variable with a wait_until which ~call_every() can interrupt before the duration times out. This ensures a more timely shutdown, should that be important.

#include <chrono>
#include <condition_variable>
#include <functional>
#include <mutex>
#include <thread>

class call_every
{
std::mutex mut_;
std::condition_variable cv_;
std::function<void()> f_;
std::chrono::system_clock::duration d_;
std::chrono::system_clock::time_point run_now_;
bool quit_;
std::thread thr_;

public:
~call_every()
{
{
std::lock_guard lock{mut_};
quit_ = true;
}
cv_.notify_one();
thr_.join();
}

template <class F>
explicit call_every(F f, std::chrono::system_clock::duration d)
: f_{std::move(f)}
, d_{d}
, run_now_{std::chrono::system_clock::now()}
, quit_{false}
, thr_{&call_every::run, this}
{
}

private:
void run()
{
while (true)
{
f_();
run_now_ += d_;
std::unique_lock lock{mut_};
if (cv_.wait_until(lock, run_now_, [this]() {return quit_;}))
break;
}
}
};

Executing a function at specific intervals

Why do you need a timer for this?

You could just measure the execution time and take a sleep according to the relation of elapsed time to desired interval duration.

Example:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>

int main() {
srand(1);
for (;;) {
double interval = 10; /* seconds */

/* start time */
time_t start = time(NULL);

/* do something */
int duration = rand() % 13;
printf("%2d seconds of work started at %s", duration, ctime(&start));
sleep(duration);

/* end time */
time_t end = time(NULL);

/* compute remaining time to sleep and sleep */
double elapsed = difftime(end, start);
int seconds_to_sleep = (int)(interval - elapsed);
if (seconds_to_sleep > 0) { /* don't sleep if we're already late */
sleep(seconds_to_sleep);
}
}
return 0;
}

Output:

$ gcc test.c && ./a.out
0 seconds of work started at Sun Mar 17 21:20:28 2013
9 seconds of work started at Sun Mar 17 21:20:38 2013
11 seconds of work started at Sun Mar 17 21:20:48 2013
4 seconds of work started at Sun Mar 17 21:20:59 2013
1 seconds of work started at Sun Mar 17 21:21:09 2013
^C

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

Calling a function every 1 second (precisely)

Instead of sleeping for a duration, you need to sleep until a time point. For example, if your first update is at precisely 2:00:00.000, your future updates should come as closely as possible to 2:00:01.000, 2:00:02.000, etc.

To achieve this you can dedicate a thread to updating, and after the update, goes to sleep until the next time to do a scheduled update. chrono::system_clock::time_point and this_thread::sleep_until are your tools to do this.

For example:

#include <atomic>
#include <chrono>
#include <iostream>
#include <thread>

class UpdateManager
{
public:
explicit UpdateManager() = default;

private:
static std::atomic<int> now_;
static std::atomic<bool> stop_;

struct update_thread
: private std::thread
{
~update_thread();
update_thread(update_thread&&) = default;

using std::thread::thread;
};

public:
static update_thread start();
};

void update();

// source

std::atomic<int> UpdateManager::now_{0};
std::atomic<bool> UpdateManager::stop_{false};

UpdateManager::update_thread::~update_thread()
{
if (joinable())
{
stop_ = true;
join();
}
}

UpdateManager::update_thread
UpdateManager::start()
{
return update_thread{[]
{
using namespace std;
using namespace std::chrono;
auto next = system_clock::now() + 1s;
while (!stop_)
{
update();
this_thread::sleep_until(next);
next += 1s;
}
}};
}

#include "date/date.h"

void
update()
{
using namespace date;
using namespace std;
using namespace std::chrono;
cerr << system_clock::now() << '\n';
}

// demo

int
main()
{
auto t = UpdateManager::start();
using namespace std;
this_thread::sleep_for(10s);
}

Just for demo purposes (not necessary for the logic), I'm using Howard Hinnant's, free, open-source date/time library to print the current time (UTC) to microsecond precision in order to illustrate the stability of this technique. A sample output of this program is:

2018-05-02 15:14:25.634809
2018-05-02 15:14:26.637934
2018-05-02 15:14:27.636629
2018-05-02 15:14:28.637947
2018-05-02 15:14:29.638413
2018-05-02 15:14:30.639437
2018-05-02 15:14:31.637217
2018-05-02 15:14:32.637895
2018-05-02 15:14:33.637749
2018-05-02 15:14:34.639084

How can my RSU call a function at periodic time intervals in Veins?

Using self messages is typical way of doing periodic task in a module. However, it might be problematic if you need to do several tasks. You need to create all messages first, handle them correctly and remember to cancelAndDelete them in a destructor.

You can achieve the same result with less code using Veins utility called TimerManager (added in Veins 4.7.). You need to have a member of TimerManager in the module and specify tasks in initialize. The advantage is that if you decide to add new periodic tasks later, it is as simple as adding them in initialize and TimerManager will take care of everything else. It might look like this:

class TraCIDemoRSU11p : public DemoBaseApplLayer {
public:
void initialize(int stage) override;
// ...
protected:
veins::TimerManager timerManager{this}; // define and instantiate the TimerManager
// ...
};

And initialize

void TraCIDemoRSU11p::initialize(int stage) {
if (stage == 0) { // Members and pointers initialization
}
else if (stage == 1) { // Members that require initialized other modules
// encode the reaction to the timer firing with a lambda
auto recurringCallback = [this](){
//Perform Calculations
};
// specify when and how ofthen a timer shall fire
auto recurringTimerSpec = veins::TimerSpecification(recurringCallback).interval(1);
// register the timer with the TimerManager instance
timerManager.create(recurringTimerSpec, "recurring timer");
}
}

Read more in the manual on Github: TimerManager manual. The code with comments is taken from there.



Related Topics



Leave a reply



Submit