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;
}
Related
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.
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
}
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));
}
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();
}
I have the following code snippet:
#include <signal.h>
#include <boost/asio.hpp>
#include <iostream>
void startAsyncWaitForSignal(boost::asio::io_service& ioService)
{
boost::asio::signal_set signals{ioService};
signals.add(SIGTERM);
signals.async_wait(
[&ioService](boost::system::error_code errorCode, int signalNumber)
{
std::cerr << errorCode.message() << std::endl;
if (!errorCode) {
std::cerr << "received signal " << signalNumber << std::endl;
startAsyncWaitForSignal(ioService);
}
}
);
}
int main() {
boost::asio::io_service ioService;
startAsyncWaitForSignal(ioService);
ioService.run();
}
I'd expect this program to wait, until the first SIGTERM is arrived, then wait to the next, then again to the next, ...
However the program is immediately terminates with the following output:
Operation canceled
What is the reason of this immediate operation cancel? I tried to make an io_service::work object, but that just changed the fact that ioService.run() was not finished, but the signal_set was still canceled immediately.
I am using boost 1.54. There is a bug fix related to asio/signals in 1.55, but that looks like a different issue.
When leaving startAsyncWaitForSignal() the local signal_set variable gets destroyed and the async_wait() call gets cancelled. The signal_set needs to live just a little longer. Move it out of startAsyncWaitForSignal() and pass it as a parameter, for example:
#include <signal.h>
#include <boost/asio.hpp>
#include <iostream>
void startAsyncWaitForSignal(boost::asio::io_service& ioService, boost::asio::signal_set& signals)
{
signals.async_wait(
[&ioService, &signals](boost::system::error_code errorCode, int signalNumber)
{
std::cerr << errorCode.message() << std::endl;
if (!errorCode) {
std::cerr << "received signal " << signalNumber << std::endl;
startAsyncWaitForSignal(ioService, signals);
}
}
);
}
int main() {
boost::asio::io_service ioService;
boost::asio::signal_set signals{ioService};
signals.add(SIGTERM);
startAsyncWaitForSignal(ioService, signals);
ioService.run();
}