I'm new to asio, and I'm trying to modify some examples for my purpose. One thought would be to run multiple timers and see if the behavior changes if I run io_service.run() on multiple threads. However, I'm not even getting that far as multiple timers cause a segmentation fault I don't understand.
My minimum working example is this:
#include <iostream>
#include <asio.hpp>
class printer {
public:
asio::steady_timer timer;
asio::io_service &io_service;
int count;
printer(asio::io_service &io_service) : io_service(io_service), timer(io_service, asio::chrono::milliseconds(10)) , count(0) {
timer.async_wait(std::bind(&printer::timer_func, this));
}
void timer_func() {
std::cout << "count " << ++count << ", on thread " << std::this_thread::get_id() << std::endl;
if (count < 5)
{
timer.expires_at(timer.expiry() + asio::chrono::milliseconds(10));
timer.async_wait(std::bind(&printer::timer_func, this));
}
}
};
int main()
{
const int NUM_PRINTERS = 2;
asio::io_service io;
std::vector<printer> work_timers;
for (int i = 0; i < NUM_PRINTERS; ++i) {
work_timers.emplace_back(io);
}
io.run();
std::cout << "broker completed.\n";
return 0;
}
For NUM_PRINTERS=1, this succeeds nicely:
count 1, on thread 139779481040704
count 2, on thread 139779481040704
count 3, on thread 139779481040704
count 4, on thread 139779481040704
count 5, on thread 139779481040704
broker completed.
However, for NUM_PRINTERS > 1 I get a segmentation fault:
count 1, on thread 140493102753600
Process finished with exit code 139 (interrupted by signal 11: SIGSEGV)
From my perspective, I have no idea how this can happen. Both printer objects are having their own variables, and I don't understand where this comes from. Why is there a segmentation fault?
In the constructor, you are binding a callable to this
. The printer
instances, however, are likely to be moved around while reallocating work_timers
upon insertion, leaving registered callbacks to steady_timer
invalid. A simple fix is to call work_timers.reserve(NUM_PRINTERS)
beforehand. Then it works (fix the warnings).
Apart from undefined behavior from pointer invalidation, steady_timer
s are also cancelled upon moving, so the handler was attempted to be called as a result of failure. You should really make sure the timers and their callbacks outlive the delay. If you want a more flexible printer
class, allocate those internals dynamically.