boost asio timer : run 2 timers - c++

I try to run a asynchronous timer and a synchronous timer :
Here is my code :
boost::asio::io_service io;
boost::asio::steady_timer t1(io);
boost::asio::steady_timer t2(io);
void callback(boost::system::error_code const&)
{
std::cout << "foo" << std::endl;
t1.expires_from_now(boost::chrono::seconds(1));
t1.async_wait(&callback);
}
int main(int argc, char **argv)
{
t1.expires_from_now(boost::chrono::seconds(1));
t1.async_wait(&callback);
io.run();
t2.expires_from_now(boost::chrono::seconds(5));
t2.wait();
io.run();
std::cout << "finish" << std::endl;
return EXIT_SUCCESS;
}
I would like foo to printed 5 times, and finish printed.
In this code, foo is printed every 1 second and finish is never reached.
How to achieve what I want ?
Thanks

According to the documentation of io_service::run:
The run() function blocks until all work has finished and there are no more handlers to be dispatched, or until the io_service has been stopped.
Since run blocks until there are no more handlers to be dispatched, it will block until callback has finished. However, callback registers another callback handler and run will keep blocking until it's finished... ad infinitum
If you want the callback to repeat only five times, then you need to not schedule a new callback after the fifth time.You can use a simple counter and a branch for that.

As said in user2079303's answer, your first io.run() call never returns since callback registers itself.
To achieve what you want to do, you can just modify your callback function as followed:
void callback(boost::system::error_code const&)
{
static int i = 0;
std::cout << "foo" << std::endl;
t1.expires_from_now(boost::chrono::seconds(1));
if (++i < 5) {
t1.async_wait(&callback);
} else {
i = 0; // Reset i if you want to reuse callback later with the same behaviour
}
}

Related

Understanding how multithreading works with Boost io_service

I'm learning multithreading and Boost libraries (Asio in particular) and I'm having a hard time understanding how the following code works (slightly modified from Boost.org tutorials)
#include <iostream>
#include <boost/asio.hpp>
#include <boost/thread/thread.hpp>
#include <boost/bind.hpp>
class printer
{
public:
printer(boost::asio::io_service& io)
: timer1_(io, boost::posix_time::seconds(1)),
timer2_(io, boost::posix_time::seconds(1)),
count_(0)
{
timer1_.async_wait(boost::bind(&printer::print1, this));
timer2_.async_wait(boost::bind(&printer::print2, this));
}
~printer()
{
std::cout << "Final count is " << count_ << std::endl;
}
void print1()
{
if (count_ < 10)
{
std::cout << "Timer 1: " << count_ << std::endl;
++count_;
timer1_.expires_at(timer1_.expires_at() + boost::posix_time::seconds(2));
timer1_.async_wait(boost::bind(&printer::print1, this));
}
}
void print2()
{
if (count_ < 10)
{
std::cout << "Timer 2: " << count_ << std::endl;
++count_;
timer2_.expires_at(timer2_.expires_at() + boost::posix_time::seconds(2));
timer2_.async_wait(boost::bind(&printer::print2, this));
}
}
private:
boost::asio::deadline_timer timer1_;
boost::asio::deadline_timer timer2_;
int count_;
};
void saysomething()
{
std::string whatyasay;
std::cin >> whatyasay;
std::cout << "You said " << whatyasay << std::endl;
}
int main()
{
boost::asio::io_service io;
printer p(io);
boost::thread t(boost::bind(&boost::asio::io_service::run, &io));
io.run();
std::cout << "Hey there\n";
t.join();
return 0;
}
Which results in the following output
Timer 1: 0
Timer 2: 1
Timer 1: 2
Timer 2: 3
Timer 1: 4
Timer 2: 5
Timer 1: 6
Timer 2: 7
Timer 1: 8
Timer 2: 9
Hey there
Final count is 10
What I would've expected from this code was that thread t would be in charge of running the io_service, meaning that other operations could take place in the meantime.
Instead, the code behaves as usual, aka, io.run "blocks" the code flow until the timers inside the printer object stop launching async_waits, so "hey there" is only printed after the timers are not working anymore.
But that's not all: from my understanding, io_services don't stop running after the run() method is called as long as there's work associated to them (be it a work object or, in this case, timers). With that said, since the thread is associated to the io_service, I wonder why the io_service would stop running in the first place: after all, the thread is "linked" to the io_service and keeps on running on its own; this is obviously linked to the fact that I clearly didn't understand what this thread is doing in the first place.
Things got even more complicated when I added the "saysomething" method into the pot: I wanted to be able to write something and having that string printed WHILE the 2 timers kept working. The code I used was the following:
int main()
{
boost::asio::io_service io;
printer p(io);
boost::thread t(&saysomething);
io.run();
std::cout << "Hey there\n";
t.join();
return 0;
}
With the following result:
Timer 1: 0
Timer 2: 1
Timer 1: 2
Timer 2: 3
Timer 1: 4
Timer 2: 5
Timer 1: 6
Timer 2: 7
ghg //<--- my input
You said ghg
Timer 1: 8
Timer 2: 9
Hey there
Final count is 10
It works fine, but now that there is no thread associated to the io_service, what was its purpose in the first place?
To sum up my 3 questions are:
Why isn't the "Hey there" string immediately printed rather than waiting for the io_service to stop running?
How exactly does the io_service stop running if a thread is linked to it, which should be equivalent to the io_service having work to do?
Since the thread wasn't allowing the "code flow" to move forward, and linking said thread to my method instead of the io_service didn't cause any error, what was the purpose of that thread in the first place?
Why isn't the "Hey there" string immediately printed rather than waiting for the io_service to stop running?
main's thread also blocks on the io_service before printing, so "Hey there" doesn't print until the service stops.
How exactly does the io_service stop running if a thread is linked to it, which should be equivalent to the io_service having work to do?
The thread is not what's keeping the io_service alive, the timer tasks are. The io_service is actually the one keeping the thread alive here. The work the service has is waiting on the timers, so until the timers expire, the service has work to do.
Since the thread wasn't allowing the "code flow" to move forward, and linking said thread to my method instead of the io_service didn't cause any error, what was the purpose of that thread in the first place?
The purpose of calling run from a thread is to donate that calling thread to the io_service. Until run exits, the service owns that thread, and that thread is part of the service's thread pool. Any task you post to the service may be handed to that thread while it is in the service's pool. When you added the second thread, that second thread wasn't interacting with the service at all because it didn't call run. Thus, it's not part of the service's thread pool.

What is the equivalent of Qtimer in C++ using std or boost libraries?

I have to perform some task every 5 seconds till the program exits. I don't want to use a thread here.
In QT I could do like this
QTimer *timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(update()));
timer->start(1000);
but how do I do this in c++ using std or boost libraries?
Thank you
I have to assume that, by "I don't want to use a thread", you mean you don't want to create threads in your own code every time you need a timer. That's because doing it without threads is actually quite hard.
Assuming C++11, you can actually do this with just the core language (no Boost or any other stuff needed) and using a separate class handling the threading so that all you need in your own code is something like (for example, harassing your ex partner with spam emails, a rather dubious use case):
Periodic spamEx(std::chrono::seconds(60), SendEmaiToEx);
The following complete program, compiled with g++ -std=c++11 -o periodic periodic.cpp -lpthread will run a periodic callback function every second for five seconds(a):
#include <thread>
#include <chrono>
#include <functional>
#include <atomic>
// Not needed if you take couts out of Periodic class.
#include <iostream>
class Periodic {
public:
explicit Periodic(
const std::chrono::milliseconds &period,
const std::function<void ()> &func
)
: m_period(period)
, m_func(func)
, m_inFlight(true)
{
std::cout << "Constructing periodic" << std::endl;
m_thread = std::thread([this] {
while (m_inFlight) {
std::this_thread::sleep_for(m_period);
if (m _inFlight) {
m_func();
}
}
});
}
~Periodic() {
std::cout << "Destructed periodic" << std::endl;
m_inFlight = false;
m_thread.join();
std::cout << "Destructed periodic" << std::endl;
}
private:
std::chrono::milliseconds m_period;
std::function<void ()> m_func;
std::atomic<bool> m_inFlight;
std::thread m_thread;
};
// This is a test driver, the "meat" is above this.
#include <iostream>
void callback() {
static int counter = 0;
std::cout << "Callback " << ++counter << std::endl;
}
int main() {
std::cout << "Starting main" << std::endl;
Periodic p(std::chrono::seconds(1), callback);
std::this_thread::sleep_for(std::chrono::seconds(5));
std::cout << "Ending main" << std::endl;
}
When you create an instance of Periodic, it saves the relevant information and starts a thread to do the work. The thread (a lambda) is simply a loop which first delays for the period then calls your function. It continues to do this until the destructor indicates it should stop.
The output is, as expected:
Starting main
Constructing periodic
Callback 1
Callback 2
Callback 3
Callback 4
Ending main
Destructed periodic
(a) Note that the time given above is actually the time from the end of one callback to start of the next, not the time from start to start (what I would call true cycle time). Provided your callback is sufficiently quick compared to the period, the difference will hopefully be unnoticable.
In addition, the thread does this delay no matter what, so the destructor may be delayed for up to a full period before returning.
If you do require a start-to-start period and fast clean-up, you can use the following thread instead. It does true start-to-start timing by working out the duration of the callback and only delaying by the rest of the period (or not delaying at all if the callback used the entire period).
It also uses a smaller sleep so that clean-up is fast. The thread function would be:
m_thread = std::thread([this] {
// Ensure we wait the initial period, then start loop.
auto lastCallback = std::chrono::steady_clock::now();
while (m_inFlight) {
// Small delay, then get current time.
std::this_thread::sleep_for(std::chrono::milliseconds(100));
auto timeNow = std::chrono::steady_clock::now();
// Only callback if still active and current period has expired.
if (m_inFlight && timeNow - lastCallback >= m_period) {
// Start new period and call callback.
lastCallback = timeNow;
m_func();
}
}
});
Be aware that, if your callback takes longer than the period, you will basically be calling it almost continuously (there'll be a 100ms gap at least).
You realize that QTimer does use a thread - or polls the timer in the main event loop. You can do the same. The conceptual problem you're likely having is that you don't have a UI and therefore, probably didn't create an event loop.
Here's the simplest way to leverage Boost Asio to have an event loop:
Live On Coliru
#include <boost/asio.hpp>
#include <boost/asio/high_resolution_timer.hpp>
#include <functional>
#include <chrono>
#include <iostream>
using namespace std::chrono_literals;
using boost::system::error_code;
namespace ba = boost::asio;
int main() {
ba::io_service svc; // prefer io_context in recent boost versions
ba::high_resolution_timer timer{svc};
std::function<void()> resume;
resume = [&] {
timer.expires_from_now(50ms); // just for demo, don't wait 5s but 50ms
timer.async_wait([=,&timer](error_code ec) {
std::cout << "Timer: " << ec.message() << "\n";
if (!ec)
resume();
});
};
resume();
svc.run_for(200ms); // probably getting 3 or 4 successful callbacks
timer.cancel();
svc.run(); // graceful shutdown
}
Prints:
Timer: Success
Timer: Success
Timer: Success
Timer: Success
Timer: Operation canceled
That may not make too much sense depending on the rest of your application. In such cases, you can do the same but use a separate thread (yes) to run that event loop.

How to restart boost deadline timer

I have a requirement such that my timer must be reset based on 2 conditions, whichever happens earlier.
When timer expires
When certain condition is met (like memory reaches certain limit)
I am following these steps:
boost::asio::io_service io;
boost::asio::deadline_timer t(io, boost::posix_time::seconds(1));
boost::mutex mtx1;
void run_io_service()
{
io.run();
}
void print(const boost::system::error_code& /*e*/)
{
boost::mutex::scoped_lock lock(mtx1);
std::cout << "Hello, world!\n";
t.expires_from_now(boost::posix_time::seconds(1));
t.async_wait(print);
std::cout << "Print executed\n";
}
int main()
{
t.async_wait(print);
boost::thread monitoring_thread = boost::thread(run_io_service);
boost::this_thread::sleep( boost::posix_time::seconds(2));
t.cancel();
std::cout << "Resetting Timer\n";
t.async_wait(print);
boost::this_thread::sleep( boost::posix_time::seconds(2));
t.cancel();
io.stop();
monitoring_thread.join();
return 0;
}
This code works fine till the time timer hasn't been cancelled.
Once timer has been cancelled, timer doesn't work in expected way, it doesn't work at all.
What am I doing wrong?
The first problem is that the handler will still be called if there is an error (such as it being cancelled), you need to check the error code.
void print(const boost::system::error_code& e )
{
if( e ) return; // we were cancelled
// actual error code for cancelled is boost::asio::error::operation_aborted
boost::mutex::scoped_lock lock(mtx1);
std::cout << "Hello, world!\n";
t.expires_from_now(boost::posix_time::seconds(1));
t.async_wait(print);
std::cout << "Print executed\n";
}
Secondly, when you cancel the timer, that leaves the io_service object without any work, which means the run_io_service thread will terminate and leave you without service. To keep the service alive during the whole program, give it a work object at the start of main:
int main() {
boost::asio::io_service::work work(io);
...
And.. as mentioned by sehe, you are not handling the timer safely (or std::cout). You should be locking mtx1 when you print the reset message and reset the timer, otherwise Murphy's law dictates that it may occur at the exact moment the handler is running and mess things up.
You need to set a new expiration.
In fact, you don't have to explicitly cancel in this event, because setting a new experation implicitly cancels any pending async wait.
Keep in mind that the deadline_timer object itself is not thread safe though, so you will need to keep your timer mutations synchronized.

boost asio behaviour - calling ios_service::run from multiple threads

I am trying to use boost::asio deadline timer for delayed function call as follows
#include <boost/asio.hpp>
#include "boost/thread.hpp"
#include <iostream>
class MyTest {
public:
MyTest()
:_invokeCount(0),
_handleCount(0)
{}
void handler(int i)
{
std::cout<<"\t\tHandled " <<i << std::endl;
++_handleCount;
}
void RunIOService()
{
std::cout<<"\tStarted :"<< _invokeCount<< std::endl;
_ios.run();
std::cout<<"\tFinished "<< _invokeCount << std::endl;
}
void invokeTimer()
{
std::cout<<"invoked " << ++_invokeCount << std::endl;
boost::asio::deadline_timer t(_ios, boost::posix_time::milliseconds(5));
t.async_wait(boost::bind(&MyTest::handler, this, _invokeCount));
boost::thread th = boost::thread(boost::bind(&MyTest::RunIOService, this));
}
void PrintCount()
{
std::cout<<"Count = "<< _invokeCount << std::endl;
}
void Wait()
{
while (_invokeCount > _handleCount) {
std::cout<<"X ";
Sleep(1000);
}
}
private:
int _invokeCount;
int _handleCount;
boost::asio::io_service _ios;
};
int main(int argc, char* argv[])
{
MyTest test;
for (int k=0; k<5; ++k) {
test.invokeTimer();
Sleep(40);
}
test.Wait();
test.PrintCount();
return EXIT_SUCCESS;
}
The output of this application is not as I expected:-
invoked 1
Started :1
Handled 1
Finished 1
invoked 2
Started :2
Finished 2
invoked 3
Started :3
Handled 2
Finished 3
invoked 4
Started :4
Handled 3
Finished 4
invoked 5
Started :5
Handled 4
Finished 5
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
I expected every handler to be called before ios_service::run returns and it doesn't seem so from the output ( missing output between Started:2 and Finished:2). Also, the application never exits. i.e the 5th handler never gets invoked.
What am I missing?
Thanks!
A couple of things:
You probably don't need 5 threads. Why don't you create a single thread and fire the events into that single ioservice instance running in the thread
Try using io_service::work in the thread run function to keep the io_service in scope while all your requests are handled.
When your wait finishes, stop your io_service, join your thread and let your program exit
Read here about io_service::work: http://www.boost.org/doc/libs/1_55_0/doc/html/boost_asio/reference/io_service.html
I added ios_service::reset() after each ios_service::run() and it worked as expected.
boost::asio::ioservice::reset() should be called before later set of invocations of the run().
as the boost doc say:
This function must be called prior to any second or later set of invocations of the run(), run_one(), poll() or poll_one() functions when a previous invocation of these functions returned due to the io_service being stopped or running out of work. This function allows the io_service to reset any internal state, such as a "stopped" flag.
This function must not be called while there are any unfinished calls to the run(), run_one(), poll() or poll_one() functions.

Basic timer with std::thread and std::chrono

I'm trying to implement a basic timer with the classic methods: start() and stop(). I'm using c++11 with std::thread and std::chrono.
Start method. Creates a new thread that is asleep for a given interval time, then execute a given std::function. This process is repeated while a 'running' flag is true.
Stop method. Just sets the 'running' flag to false.
I created and started a Timer object that show "Hello!" every second, then with other thread I try to stop the timer but I can't. The Timer never stops.
I think the problem is with th.join()[*] that stops execution until the thread has finished, but when I remove th.join() line obviously the program finishes before the timer start to count.
So, my question is how to run a thread without stop other threads?
#include <iostream>
#include <thread>
#include <chrono>
using namespace std;
class Timer
{
thread th;
bool running = false;
public:
typedef std::chrono::milliseconds Interval;
typedef std::function<void(void)> Timeout;
void start(const Interval &interval,
const Timeout &timeout)
{
running = true;
th = thread([=]()
{
while (running == true) {
this_thread::sleep_for(interval);
timeout();
}
});
// [*]
th.join();
}
void stop()
{
running = false;
}
};
int main(void)
{
Timer tHello;
tHello.start(chrono::milliseconds(1000),
[]()
{
cout << "Hello!" << endl;
});
thread th([&]()
{
this_thread::sleep_for(chrono::seconds(2));
tHello.stop();
});
th.join();
return 0;
}
Output:
Hello!
Hello!
...
...
...
Hello!
In Timer::start, you create a new thread in th and then immediately join it with th.join(). Effectively, start won't return until that spawned thread exits. Of course, it won't ever exit because nothing will set running to false until after start returns...
Don't join a thread until you intend to wait for it to finish. In this case, in stop after setting running = false is probably the correct place.
Also - although it's not incorrect - there's no need to make another thread in main to call this_thread::sleep_for. You can simply do so with the main thread:
int main()
{
Timer tHello;
tHello.start(chrono::milliseconds(1000), []{
cout << "Hello!" << endl;
});
this_thread::sleep_for(chrono::seconds(2));
tHello.stop();
}
Instead of placing the join in start place it after running = false in stop. Then the stop method will effectively wait until the thread is completed before returning.