boost async_wait return handler never gets called - c++

I am working with the boost::asio tcp, version 1.57, creating a custom server/client, roughly following this example: Async_Tcp_Client , but I'm running the io_service run() in it's own thread per server/client. Also, there can be multiple server/clients per application.
Following the example I put my await_output function to sleep when I DON'T want to send a Message, and waking it up when I do want to send one (via async_write). After a varying amount of send-operations (sometimes less then 10, sometimes several thousand) I run into strange behaviour of my await_output Deadline (a boost deadline timer).
At some point, the async_wait against the timer just "disappears" and doesn't return when I cancel the deadline to send a message.
The transmit function, that is called by the Application owning the Client/Server (only by the application though, I guess it is not very threadsafe);
The await_output function that is waiting on the mOutputQueueDeadline;
And the handle_write function:
void SocketTcp::transmit(std::string pMsg) {
if (mStopped)
{ return; }
mOutputQueue.push(pMsg); // a global queue
// Signal that the output queue contains messages. Modifying the expiry
// will wake the output actor, if it is waiting on the timer.
size_t quits = mOutputQueueDeadline.expires_at(boost::posix_time::neg_infin);
//this returns '0' when the error occurs
}
void SocketTcp::await_output(const boost::system::error_code& ec)
{
if (mStopped)
{ return; }
if (mOutputQueue.empty())
{
size_t quits = mOutputQueueDeadline.expires_at(boost::posix_time::pos_infin);
mOutputQueueDeadline.async_wait(boost::bind(&SocketTcp::await_output, this, _1));
//this async_wait starts a wait on the deadline, that sometimes never returns!
}
else
{
boost::asio::async_write(mSocket,
boost::asio::buffer(mOutputQueue.front()),
boost::bind(&SocketTcp::handle_write, this, _1));
}
}
void SocketTcp::handle_write(const boost::system::error_code& ec)
{
if (mStopped)
{ return; }
if(!ec)
{
mOutputQueue.pop(); //remove sent element from queue
boost::system::error_code errcode;
await_output(errcode); //start the waiting actor for outgoing messages
}
else
{
mConnected = false; //update the connection status
this->stop();
}
}
I tried implementing a workaround, restarting the await_output in transmit() when expire_at returns 0, but that leads to TWO actors beeing awakened the next time I send a message, and then running into a crash (String iterator not dereferencable - the design doesn't allow for parallel send OP, much less trying to send the same message...)
I tried debugging with the BOOST_ASIO_ENABLE_HANDLER_TRACKING option, and found the error here:
#asio|1468415460.456019|0|deadline_timer#000000000050AB88.cancel //transmit cancels the timer
#asio|1468415460.456019|>474|ec=system:995 //await_output is called
#asio|1468415460.456019|474*479|socket#000000000050A9D8.async_send //starts the async send
#asio|1468415460.457019|<474|
#asio|1468415460.457019|>479|ec=system:0,bytes_transferred=102 //async send returns to it's handler
#asio|1468415460.457019|479|deadline_timer#000000000050AB88.cancel
//this cancel op is the only difference to the 'normal' order,
//not sure where it originates though!!
#asio|1468415460.457019|479*480|deadline_timer#000000000050AB88.async_wait //the handler starts the new async wait
//handler 480 never gets called when the deadline is canceled the next time
#asio|1468415460.457019|<479|
I'm pretty new to c++ as well as the stackoverflow (even though it has already safed me multiple times!) so please tell me if I can improve my question somehow!

Related

App crashes when it takes too long to reply in a ZMQ REQ/REP pattern

I am writing a plugin that interfaces with a desktop application through a ZeroMQ REQ/REP request-reply communication archetype. I can currently receive a request, but the application seemingly crashes if a reply is not sent quick enough.
I receive the request on a spawned thread and put it in a queue. This queue is processed in another thread, in which the processing function is invoked by the application periodically.
The message is correctly being received and processed, but the response cannot be sent until the next iteration of the function, as I cannot get the data from the application until then.
When this function is conditioned to send the response on the next iteration, the application will crash. However, if I send fake data as the response soon after receiving the request, in the first iteration, the application will not crash.
Constructing the socket
zmq::socket_t socket(m_context, ZMQ_REP);
socket.bind("tcp://*:" + std::to_string(port));
Receiving the message in the spawned thread
void ZMQReceiverV2::receiveRequests() {
nInfo(*m_logger) << "Preparing to receive requests";
while (m_isReceiving) {
zmq::message_t zmq_msg;
bool ok = m_respSocket.recv(&zmq_msg, ZMQ_NOBLOCK);
if (ok) {
// msg_str will be a binary string
std::string msg_str;
msg_str.assign(static_cast<char *>(zmq_msg.data()), zmq_msg.size());
nInfo(*m_logger) << "Received the message: " << msg_str;
std::pair<std::string, std::string> pair("", msg_str);
// adding to message queue
m_mutex.lock();
m_messages.push(pair);
m_mutex.unlock();
}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
nInfo(*m_logger) << "Done receiving requests";
}
Processing function on seperate thread
void ZMQReceiverV2::exportFrameAvailable()
// checking messages
// if the queue is not empty
m_mutex.lock();
if (!m_messages.empty()) {
nInfo(*m_logger) << "Reading message in queue";
smart_target::SMARTTargetCreateRequest id_msg;
std::pair<std::string, std::string> pair = m_messages.front();
std::string topic = pair.first;
std::string msg_str = pair.second;
processMsg(msg_str);
// removing just read message
m_messages.pop();
//m_respSocket.send(zmq::message_t()); wont crash if I reply here in this invocation
}
m_mutex.unlock();
// sending back the ID that has just been made, for it to be mapped
if (timeToSendReply()) {
sendReply(); // will crash, if I wait for this to be exectued on next invocation
}
}
My research shows that there is no time limit for the response to be sent, so this, seeming to be, timing issue, is strange.
Is there something that I am missing that will let me send the response on the second iteration of the processing function?
Revision 1:
I have edited my code, so that the responding socket only ever exists on one thread. Since I need to get information from the processing function to send, I created another queue, which is checked in the revised the function running on its own thread.
void ZMQReceiverV2::receiveRequests() {
zmq::socket_t socket = setupBindSocket(ZMQ_REP, 5557, "responder");
nInfo(*m_logger) << "Preparing to receive requests";
while (m_isReceiving) {
zmq::message_t zmq_msg;
bool ok = socket.recv(&zmq_msg, ZMQ_NOBLOCK);
if (ok) {
// does not crash if I call send helper here
// msg_str will be a binary string
std::string msg_str;
msg_str.assign(static_cast<char *>(zmq_msg.data()), zmq_msg.size());
NLogger::nInfo(*m_logger) << "Received the message: " << msg_str;
std::pair<std::string, std::string> pair("", msg_str);
// adding to message queue
m_mutex.lock();
m_messages.push(pair);
m_mutex.unlock();
}
std::this_thread::sleep_for(std::chrono::milliseconds(100));
if (!sendQueue.empty()) {
sendEntityCreationMessage(socket, sendQueue.front());
sendQueue.pop();
}
}
nInfo(*m_logger) << "Done receiving requests";
socket.close();
}
The function sendEntityCreationMessage() is a helper function that ultimately calls socket.send().
void ZMQReceiverV2::sendEntityCreationMessage(zmq::socket_t &socket, NUniqueID id) {
socket.send(zmq::message_t());
}
This code seems to be following the thread safety guidelines for sockets. Any suggestions?
Q : "Is there something that I am missing"
Yes,the ZeroMQ evangelisation, called a Zen-of-Zero, since ever promotes never try to share a Socket-instance, never try to block and never expect the world to act as one wishes.
This said, avoid touching the same Socket-instance from any non-local thread, except the one that has instantiated and owns the socket.
Last, but not least, the REQ/REP-Scalable Formal Communication Pattern Archetype is prone to fall into a deadlock, as a mandatory two-step dance must be obeyed - where one must keep the alternating sequence of calling .send()-.recv()-.send()-.recv()-.send()-...-methods, otherwise the principally distributed-system tandem of Finite State Automata (FSA) will unsalvageably end up in a mutual self-deadlock state of the dFSA.
In case one is planning to professionally build on ZeroMQ, the best next step is to re-read the fabulous Pieter HINTJENS' book "Code Connected: Volume 1". A piece of a hard read, yet definitely worth one's time, sweat, tears & efforts put in.

use io_service::post (boost) when deadline_timer is waiting

I have a problem while using deadline_timer and io_service::post as below:
#include "boost/asio.hpp"
#include "boost/thread.hpp"
int main()
{
boost::asio::io_service io_service;
boost::asio::deadline_timer timer1(io_service);
boost::asio::deadline_timer timer2(io_service);
timer1.expires_from_now(boost::posix_time::seconds(1));
timer1.async_wait([](const boost::system::error_code& error) {
boost::this_thread::sleep(boost::posix_time::seconds(5));
printf("1 ");
});
timer2.expires_from_now(boost::posix_time::seconds(2));
timer2.async_wait([](const boost::system::error_code& error) {
printf("2 ");
});
boost::thread t([&io_service]() {
boost::this_thread::sleep(boost::posix_time::seconds(5));
io_service.post([]() {
printf("3 ");
});
io_service.post([]() {
printf("4 ");
});
});
io_service.run();
t.join();
getchar();
return 0;
}
I thougth that the result is "1 2 3 4" but the result is "1 3 4 2". Anyone can show me how to the callback of timer2(print "2") is performed before as the result "1 2 3 4" with boost library (and don't change the expire time of timer1 and timer2).
Thanks very much!
This is actually a pretty complicated example.
The io_service will run on the main thread. Here is the order of operations
Main Thread:
Request Timer at T0 + 1
Request Timer at T0 + 2
Spawn thread
Execute all pending io (io_service.run())
Secondary Thread:
Sleep 5 seconds
Request Timer
Request Timer
First of all, nothing will execute in the io_service until io_service.run() is called.
Once io_service.run() is called, a timer for 1 second in the future is scheduled. When that timer fires, it first sleeps for 5 seconds before printing 1.
While that thread is executing, the secondary thread also comes up, and sleeps for 5 seconds. This thread is setup and scheduled before the timer executing in the handler for timer1 is completed. Since both of these threads sleep for 5 seconds, '2' and '3' are immediately posted to the io_service.
Now things get a bit tricky. It seems likely that the timeout for timer2 should have expired by now (it being at least 5 seconds in the future), but there were two commands directly posted to the io_service while it was handling timer1.
It seems that in the implementation details, boost gives priority to directly posted actions over deadline timer actions.
the first timer expiration blocks the io (main) thread from running, in the mean time the other thread posts a couple of items to asio work queue, once timer 1's callback completes, the second timers expiration is processed which causes the callback to be queued but not executed. since "3" & "4" where already queued (while "1" was blocking the main thread), they go ahead of "2"
The point of asio is to not block. By putting long running work in the first timers callback (the sleep) you have prevented the io thread from running in a timely manner. You should offload that work into a dedicated thread, and post its completion back to asio.
The io_service makes no guarantees about the invocation order of handlers. In theory, the handlers could be invoked in any order, with some permutations being significantly unlikely.
If handlers need to be invoked in a very specific order, then consider restructing the asynchronous call chains in a manner that enforces the desired handler chain. Additionally, one may find it necessary to use the guaranteed order of handler invocation that strand provides. Consider not trying to control complex handler invocations through with brittle sleeps and timers.
Your first problem is that you're trying to block inside a handler:
timer1.expires_from_now(boost::posix_time::seconds(1));
timer1.async_wait([](const boost::system::error_code& error) {
boost::this_thread::sleep(boost::posix_time::seconds(5)); // <--- HERE
printf("1 ");
});
What happens in the above code is that after timer1 waits for one second, it posts the callback to the io_service. Inside the io_service::run function this callback is executed but this execution happens inside the main thread, so it halts for five seconds, preventing timer2 from posting its handler for execution into io_service. It does so until the sixth second of the program execution (6 = 5+1).
Meanwhile the thread t gets executed and at fifth second of program execution it posts those two printf("3") and printf("4") to io_service.
boost::thread t([&io_service]() {
boost::this_thread::sleep(boost::posix_time::seconds(5));
io_service.post([]() {
printf("3 ");
});
io_service.post([]() {
printf("4 ");
});
});
Once the handler from timer1 unblocks, it allows timer2 to post its handler to io_service. That again happens at sixth second of program exectuion, that is, once the printf("3") and printf("4") have already been posted!
All in all, I believe what you're looking for is this:
#include "boost/asio.hpp"
#include "boost/thread.hpp"
int main()
{
boost::asio::io_service io_service;
boost::optional<boost::asio::io_service::work> work(io_service);
boost::asio::deadline_timer timer1(io_service);
boost::asio::deadline_timer timer2(io_service);
timer1.expires_from_now(boost::posix_time::seconds(1));
timer1.async_wait([](const boost::system::error_code& error) {
printf("1 ");
});
timer2.expires_from_now(boost::posix_time::seconds(2));
timer2.async_wait([](const boost::system::error_code& error) {
printf("2 ");
});
boost::thread t([&io_service, &work]() {
boost::this_thread::sleep(boost::posix_time::seconds(5));
io_service.post([]() {
printf("3 ");
});
io_service.post([&work]() {
printf("4 ");
work = boost::none;
});
});
io_service.run();
t.join();
return 0;
}

Boost.Asio: Why the timer is executed only once?

I have a function called read_packet. This function remains blocked while there is no connection request or the timer is signaled.
The code is the following:
std::size_t read_packet(const std::chrono::milliseconds& timeout,
boost::system::error_code& error)
{
// m_timer_ --> boost::asio::high_resolution_timer
if(!m_is_first_time_) {
m_is_first_time = true;
// Set an expiry time relative to now.
m_timer_.expires_from_now( timeout );
} else {
m_timer_.expires_at( m_timer_.expires_at() + timeout );
}
// Start an asynchronous wait.
m_timer_.async_wait(
[ this ](const boost::system::error_code& error){
if(!error) m_is_timeout_signaled_ = true;
}
);
auto result = m_io_service_.run_one();
if( !m_is_timeout_signaled_ ) {
m_timer_.cancel();
}
m_io_service_.reset();
return result;
}
The function works correctly while not receiving a connection request. All acceptances of requests are asynchronous.
After accepting a connection, the run_one() function does not remains blocked the time set by the timer. The function always returns 1 (one handle has been processed). This handle corresponds to the timer.
I do not understand why this situation occurs.
Why the function is not blocked the time required for the timer?
Cheers.
NOTE: This function is used in a loop.
UPDATE:
I have my own io_service::run() function. This function performs other actions and tasks. I want to listen and process the network level for a period of time:
If something comes on the network level, io_service::run_one() returns and read_packet() returns the control to my run() function.
Otherwise, the timer is fired and read_packet() returns the control to my run() function.
Everything that comes from the network level is stored in a data structure. Then my run() function operates on that data structure.
It also runs other options.
void run(duration timeout, boost::system::error_code& error)
{
time_point start = clock_type::now();
time_point deadline = start + timeout;
while( !stop() ) {
read_packet(timeout, error);
if(error) return;
if(is_timeout_expired( start, deadline, timeout )) return;
// processing network level
// other actions
}
}
In my case, the sockets are always active until a client requests the closing of the connection.
During a time slot, you manage the network level and for another slot you do other things.
After reading the question more closely I got the idea that you are actually trying to use Asio to get synchronous IO, but with a timeout on each read operation.
That's not what Asio was intended for (hence, the name "Asynchronous IO Library").
But sure, you can do it if you insist. Like I said, I feel you're overcomplicating things.
In the completion handler of your timer, just cancel the socket operation if the timer had expired. (Note that if it didn't, you'll get operation_aborted, so check the error code).
Small selfcontained example (which is what you should always do when trying to get help, by the way):
Live On Coliru
#include <boost/asio.hpp>
#include <boost/asio/high_resolution_timer.hpp>
#include <iostream>
struct Program {
Program() { sock_.connect({ boost::asio::ip::address_v4{}, 6771 }); }
std::size_t read_packet(const std::chrono::milliseconds &timeout, boost::system::error_code &error) {
m_io_service_.reset();
boost::asio::high_resolution_timer timer { m_io_service_, timeout };
timer.async_wait([&](boost::system::error_code) {
sock_.cancel();
});
size_t transferred = 0;
boost::asio::async_read(sock_, boost::asio::buffer(buffer_), [&](boost::system::error_code ec, size_t tx) {
error = ec;
transferred = tx;
});
m_io_service_.run();
return transferred;
}
private:
boost::asio::io_service m_io_service_;
using tcp = boost::asio::ip::tcp;
tcp::socket sock_{ m_io_service_ };
std::array<char, 512> buffer_;
};
int main() {
Program client;
boost::system::error_code ec;
while (!ec) {
client.read_packet(std::chrono::milliseconds(100), ec);
}
std::cout << "Exited with '" << ec.message() << "'\n"; // operation canceled in case of timeout
}
If the socket operation succeeds you can see e.g.:
Exited with 'End of file'
Otherwise, if the operation didn't complete within 100 milliseconds, it will print:
Exited with 'Operation canceled'
See also await_operation in this previous answer, which generalizes this pattern a bit more:
boost::asio + std::future - Access violation after closing socket
Ok, The code is incorrect. When the timer is canceled, the timer handler is always executed. For this reason io_service::run_one() function is never blocked.
More information: basic_waitable_timer::cancel
Thanks for the help.

Including a ping timeout feature

I have Server A that receive's updates from Server B. I would like to add functionality to Server A where if it does not receive a message(server B will send update and ping messages) in 1 minutes time, Server A will go into a paused state and wait for messages to come in again.
I was looking into a boost::asio::deadline_timer, but I cannot figure out if it is possible, or if you can run this asynchronously. I tried a class that runs in its own thread and uses a deadline timer, but I am unable to cancel and restart the deadline timer. Here is some example code I used for that.
The implementation:
void ping_timeout::reset_timer()
{
ping_timeout_.cancel();
ping_timeout_.expires_from_now(boost::posix_time::seconds(60));
//Call to clear the cache of a static class, which is the paused state I would like
ping_timeout_.async_wait(boost::bind(&cache::empty_cache));
io_.run();
}
I am unable to cancel the deadline timer from my main thread of execution by calling reset timer, I am guessing because io_.run() is waiting for the 60 seconds to expire.
Is there any modification I can do, any any libraries out there that I can us to achieve the results I would like? Any help would be appreciated.
Thank you
Edit:
Main Loop:
ping_timeout timeout;
boost::thread(boost::bind(&cache::run_io,boost::ref(service)));
while(true)
{
std::string message = s_recv(subscriber);
}
if(message.compare("UPDATE") == 0)
{
//Process update
}
else if(message.compare("PING") == 0)
{
timeout.reset_timer();
}
}
Edit 2:
Working code:
void cache::process_cache()
{
boost::asio::io_service service;
boost::asio::io_service::work work(service);
boost::thread(boost::bind(&cache::run_io,boost::ref(service)));
boost::asio::deadline_timer timer(service,boost::posix_time::seconds(60));
timer.async_wait(boost::bind(&cache::empty_cache,boost::asio::placeholders::error));
while(true)
{
std::string message = s_recv(subscriber);
if(message.compare("UPDATE") == 0)
{
//Process update
}
else if(message.compare("PING") == 0)
{
timer.cancel();
timer.expires_from_now(boost::posix_time::seconds(60));
timer.async_wait(boost::bind(&cache::empty_cache,boost::asio::placeholders::error));
}
}
}
void cache::empty_cache(const boost::system::error_code& e)
{
if(e.value() == 0)
{
//Clear cache
}
}
void cache::run_io(boost::asio::io_service& io)
{
io.run();
}
boost::asio::io_service::run() is a blocking call. In your specific case, you should avoid calling that in your main thread.
Note: In a typical async-driven app, you should build your app around the run method.
As for the timer code logic, something like that should work :
boost::asio::io_service service;
// Creates a work object to prevent the thread from exiting after the first job is done
boost::asio::io_service::work work(service);
// Creates the timer and post the aync wait now, will only start when service.run() is called
boost::asio::deadline_timer timer(service, boost::posix_time::seconds(60));
timer.async_wait(boost::bind(&cache::empty_cache, ...));
// Starts the worker thread to allow the timer to asynchronously waits
boost::thread ping_thread(boost::bind(&boost::asio::io_service::run, &service));
while (true) // you should add a condition in order to leave if the timer expires
{
std::string message = s_recv(subscriber);
/**/ if (message == "UPDATE")
{
// Process update
}
else if (message == "PING")
{
// Cancel the current timer
timer.cancel();
// Start another async wait
timer.async_wait(boost::bind(&cache::empty_cache, ...));
}
}

How to exit a program at particuliar time while main loop is listening for message?

In the main program main loop, I'm listening on a EMS topic by calling tibemsMsgConsumer_Receive. Meanwhile, I want to exit the program at specific time, say 5PM. How can I implement this?
I tried to use the following code but it doesn't work properly in the case there is no message received.
Is there a way I can exit the program when 'while' loop is stuck there?
while (1)
{
status = tibemsMsgConsumer_Receive(m_CmbsSpreadMatrixSubscriber, &msg);
if (status == TIBEMS_OK)
{
DoSomething();
}
if (getRunTime("hour").c_str()) >= 18)
{
exit(0);
}
}
Use tibemsMsgConsumer_ReceiveTimeout() and set an appropriate timeout to check your exit condition repeatedly.
From the description on that page:
This function consumes the next message from the consumer’s destination. When the destination does not have any messages ready, this function blocks:
If a message arrives at the destination, this call immediately consumes that message and returns.
If the (non-zero) timeout elapses before a message arrives, this call returns TIBEMS_TIMEOUT.
If another thread closes the consumer, this call returns TIBEMS_INTR.
before starting the main loop listening on message, I start a thread.
boost::thread aThread(&threadFunc);
and in the thread function I simply count time and exit the program. Not sure if
it's safe and right or not...
void threadFunc()
{
while (true)
{
wait(60);
if (atoi(getRunTime("hour").c_str()) >= 18)
{
Log("Now it's 6PM, let's stop and get back tomorrow.");
exit(0);
}
}
}