Re-using Boost's timer objects - c++

I modify the code from Boost's Timer 2 tutorial here
for a periodic printout:
#include <boost/date_time/posix_time/posix_time.hpp>
void print(const boost::system::error_code& /*e*/)
{
static int i = 0;
i++;
std::cout << i << std::endl;
}
int main()
{
while(1)
{
boost::asio::io_context io;
boost::asio::deadline_timer t(io, boost::posix_time::seconds(1));
t.async_wait(&print);
t.wait();
io.run();
}
}
What I don't get is if I take the first two lines outside of while(1), it will not work properly. Is there a way to create these objects and reuse them? Thanks.

You need to schedule the next timer event with
expires_at http://www.boost.org/doc/libs/1_66_0/doc/html/boost_asio/reference/basic_deadline_timer/expires_at.html
or expires_from_now http://www.boost.org/doc/libs/1_66_0/doc/html/boost_asio/reference/basic_deadline_timer/expires_from_now.html
So, like:
#include <boost/asio.hpp>
#include <iostream>
void print(boost::system::error_code ec) {
static int i = 0;
if (ec != boost::asio::error::operation_aborted) {
i++;
}
std::cout << i << " (" << ec.message() << ")" << std::endl;
}
int main() {
boost::asio::io_service io;
boost::asio::deadline_timer t(io);
while (1) {
t.expires_from_now(boost::posix_time::seconds(1));
t.async_wait(&print);
if (io.stopped()) { io.reset(); }
io.run();
}
}

OK, that part is apparently in Timer 3 tutorial. Also, the documentations of 1.66 has missing info. Gotta change to 1.65 to see it.

Related

boost asio async_read_some timeout

I use this code using async_read_some with timeout
readdata=0;
port_->async_read_some(boost::asio::buffer(vector),
boost::bind(readCallback));
//init async timer
boost::asio::deadline_timer timer(io);
timer.async_wait(boost::bind(timeoutHandler));
timer.expires_from_now(boost::posix_time::seconds(5));
io.reset();
do {
io.run_one();
}
while (readdata==0);
here are my callbacks
void readCallback()
{
std::cout << "READ CALLBACK: "<<x<<std::endl;
readdata=1;
return;
}
void timeoutHandler()
{
std::cout << "TIMEOUT CALLBACK: "<<x<<std::endl;
readdata=1;
}
my Problem is that timeoutHandler is is executed instantly and not after 5 seconds
Simple mistake. You should be doing expires_from_now before calling async_wait.
#include <iostream>
#include <asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
int main() {
asio::io_service io_s;
asio::deadline_timer timer(io_s);
timer.expires_from_now(boost::posix_time::seconds(5));
timer.async_wait([](auto err_c) { std::cout << "After 5 seconds" << std::endl; } );
io_s.reset();
io_s.run();
return 0;
}

Boost timer expires immediately

I run boost deadline_timer and do async_wait, but timer cancelled immediately. What i am doing wrong? I run ioService in my main file.
Thank you for any possible help
class A(boost::asio:io_service& ioService):
m_timer(ioService)
{
m_timer.expires_at(boost::posix_time::pos_infin);
m_timer.async_wait([this](const boost::system::error_code& ec)
{
std::cout << "Timer callback " << ec.message() << std::endl;
});
Check the lifetime of your A object.
E.g. if you do this:
#include <boost/asio.hpp>
#include <iostream>
struct A {
A(boost::asio::io_service& ioService) : m_timer(ioService)
{
m_timer.expires_at(boost::posix_time::pos_infin);
m_timer.async_wait(
[this](const boost::system::error_code& ec) { std::cout << "Timer callback " << ec.message() << std::endl; }
);
}
boost::asio::deadline_timer m_timer;
};
int main()
{
boost::asio::io_service svc;
{
A a(svc);
}
svc.run();
}
The timer will have been canceled even before run() is invoked.
The following will do what you expected
int main()
{
boost::asio::io_service svc;
{
A a(svc);
svc.run();
} // A destructed after `run()` completes
}

io_service deadline timer does not work periodically

i want to make a timer with 10s periodically in the class inside, but it does not work. It will print count in 10s at the first time. But after that, it does not wait another 10s. the specific code.
#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
class test {
boost::asio::io_service& a;
boost::asio::deadline_timer t;
int count;
void print(const boost::system::error_code& /*e*/)
{
while(true)
{
std::cout << count << " ";
++(count);
t.expires_at(t.expires_at() + boost::posix_time::seconds(10));
t.async_wait(boost::bind(&test::print, this, boost::asio::placeholders::error));
}
}
public:
test(boost::asio::io_service& io) : a(io), t(io, boost::posix_time::seconds(10)) {
count = 0;
};
void start() {
t.async_wait(boost::bind(&test::print, this, boost::asio::placeholders::error));
}
};
int main()
{
boost::asio::io_service io;
int count = 0;
test b(io);
b.start();
io.run();
return 0;
}
Your print() function has an unnecessary while(true) loop. Once we remove that, we notice that the output doesn't come right away; that's because std::cout is line-buffered and we never write a newline. Here's the full fixed function:
void print(const boost::system::error_code& /*e*/)
{
std::cout << count << " " << std::flush;
++(count);
t.expires_at(t.expires_at() + boost::posix_time::seconds(10));
t.async_wait(boost::bind(&test::print, this, boost::asio::placeholders::error));
}

boost asio deadline_timer async_wait(N seconds) twice within N seconds cause operation canceled

What I want is when one message queue receives an int N, the handler function will be called after N seconds. below is my code.
It runs OK if the duration seconds of two near message queue is larger than the int N, but the handler will print "Operation canceled" in one handler when the duration seconds between two received message queues are smaller than N, which is not what I want.
I'd appreciate a lot for any help.
#include <boost/asio.hpp>
#include <zmq.h>
#include <boost/thread.hpp>
#include <iostream>
boost::asio::io_service io_service;
void* context = zmq_ctx_new();
void* sock_pull = zmq_socket(context, ZMQ_PULL);
void handler(const boost::system::error_code &ec) {
std::cout << "hello, world" << "\t" << ec.message() << std::endl;
}
void run() {
io_service.run();
}
void thread_listener() {
int nRecv;
boost::asio::deadline_timer timer(io_service, boost::posix_time::seconds(0));
while( true ) {
zmq_recv(sock_pull, &nRecv, sizeof(nRecv), 0);
std::cout << nRecv << std::endl;
timer.expires_from_now(boost::posix_time::seconds(nRecv));
timer.async_wait(handler);
}
}
int main(int argc, char* argv[]) {
boost::asio::io_service::work work(io_service);
zmq_bind(sock_pull, "tcp://*:60000");
boost::thread tThread(thread_listener);
boost::thread tThreadRun(run);
tThread.join();
tThreadRun.join();
return 0;
}
When you call
timer.expires_from_now(boost::posix_time::seconds(nRecv));
this, as the documentation states, cancels any async timer pending.
If you want to have overlapping requests in flight at a given time, one timer is clearly not enough. Luckily there is a wellknown pattern around bound shared pointers in Asio that you can use to mimick a "session" per response.
Say you define a session to contain it's own private timer:
struct session : boost::enable_shared_from_this<session> {
session(boost::asio::io_service& svc, int N) :
timer(svc, boost::posix_time::seconds(N))
{
// Note: shared_from_this is not allowed from ctor
}
void start() {
// it's critical that the completion handler is bound to a shared
// pointer so the handler keeps the session alive:
timer.async_wait(boost::bind(&session::handler, shared_from_this(), boost::asio::placeholders::error));
}
private:
void handler(const boost::system::error_code &ec) {
std::cout << "hello, world" << "\t" << ec.message() << std::endl;
}
boost::asio::deadline_timer timer;
};
Now, it's trivial to replace the code that used the hardcoded timer instance:
timer.expires_from_now(boost::posix_time::seconds(nRecv));
timer.async_wait(handler);
with the session start:
boost::make_shared<session>(io_service, nRecv)->start();
A fully working example (with suitably stubbed ZMQ stuff): Live On Coliru
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/make_shared.hpp>
#include <iostream>
boost::asio::io_service io_service;
/////////////////////////////////////////////////////////////////////////
// I love stubbing out stuff I don't want to install just to help others
enum { ZMQ_PULL };
static void* zmq_ctx_new() { return nullptr; }
static void* zmq_socket(void*,int) { return nullptr; }
static void zmq_bind(void*,char const*) {}
static void zmq_recv(void*,int*data,size_t,int)
{
boost::this_thread::sleep_for(boost::chrono::milliseconds(rand()%1000));
*data = 2;
}
// End of stubs :)
/////////////////////////////////////////////////////////////////////////
void* context = zmq_ctx_new();
void* sock_pull = zmq_socket(context, ZMQ_PULL);
struct session : boost::enable_shared_from_this<session> {
session(boost::asio::io_service& svc, int N) :
timer(svc, boost::posix_time::seconds(N))
{
// Note: shared_from_this is not allowed from ctor
}
void start() {
// it's critical that the completion handler is bound to a shared
// pointer so the handler keeps the session alive:
timer.async_wait(boost::bind(&session::handler, shared_from_this(), boost::asio::placeholders::error));
}
~session() {
std::cout << "bye (session end)\n";
}
private:
void handler(const boost::system::error_code &ec) {
std::cout << "hello, world" << "\t" << ec.message() << std::endl;
}
boost::asio::deadline_timer timer;
};
void run() {
io_service.run();
}
void thread_listener() {
int nRecv = 0;
for(int n=0; n<4; ++n) {
zmq_recv(sock_pull, &nRecv, sizeof(nRecv), 0);
std::cout << nRecv << std::endl;
boost::make_shared<session>(io_service, nRecv)->start();
}
}
int main() {
auto work = boost::make_shared<boost::asio::io_service::work>(io_service);
zmq_bind(sock_pull, "tcp://*:60000");
boost::thread tThread(thread_listener);
boost::thread tThreadRun(run);
tThread.join();
work.reset();
tThreadRun.join();
}

how can it do other work except "async_wait" in one single thread using boost.asio.deadline_timer

I rewrite a boost.asio example "Timer.3 - Binding arguments to a handler". I think "worker" can work forever and "print" can be called each second. But "print" only is called once. It is very diffcult for me to think why.
If this can't work,how can I do other things except "async_wait" in one single thread.
#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
int num = 0;
void worker(){
while(1){
++num;
}
}
void print(const boost::system::error_code& /*e*/,
boost::asio::deadline_timer* t, int* count)
{
std::cout << *count << "\n";
++(*count);
t->expires_at(t->expires_at() + boost::posix_time::seconds(1));
t->async_wait(boost::bind(
print, boost::asio::placeholders::error, t, count
));
if(*count == 1){
worker();
}
}
int main()
{
boost::asio::io_service io;
int count = 0;
boost::asio::deadline_timer t(io, boost::posix_time::seconds(1));
t.async_wait(boost::bind(print,
boost::asio::placeholders::error, &t, &count
));
io.run();
std::cout << "Final count is " << count << "\n";
return 0;
}
You have an infinite loop
void worker() {
while(1) {
++num;
}
}
so control never returns the first time print() is invoked.