Boost::Asio synchronous I/O operation with timeout

A

Antonio Di Monaco

Hi,

I don't know if I'm [OT] about my question here, but I didn't find any
Boost-related groups.

I have a question about Boost Asio, better say a need of clarification.
Let me summarize my problem
first. I need to control a TCP device, that works like that:

a) it always wait for a command, and returns a response
b) both command and response lengths are known in advance, so I know how
many bytes I expect in both directions
c) sequence command/response is atomic, i.e. it doesn't accept another
command before having replied to the first one

So I implemented synchronous read/write operations using Boost Asio. I
clarify that my solution works perfectly, I just need
to know if it was implemented in the way it should be, cause it was a
result of "try-and-pray", and maybe my result isn't the
proper way to manage this problem.

For the sake of brevity, I'm posting only write method, cause read one
has the same layout:

int IONetworkSocket::doWrite(const std::vector< unsigned char > &vData)
{
boost::system::error_code timerResult;
boost::system::error_code writeResult;
std::size_t bytesWritten = 0;

bool timeout = false, ioError = false, ignoreTimeout = false,
ignoreIoError = false;
unsigned int transaction = _currentTransaction;

boost::asio::deadline_timer timer(ioService());

timer.expires_from_now(boost::posix_time::milliseconds(writeTimeOut()));
timer.async_wait([&timerResult, &timeout, &ignoreIoError, transaction,
this] (const boost::system::error_code &cError)
{
boost::lock_guard< boost::mutex >
guard(this->_transactionMutex);

if (transaction == this->_currentTransaction)
{
++(this->_currentTransaction);
timeout = true;
timerResult = cError;
ignoreIoError = true;
}
});

boost::asio::async_write(socket(),boost::asio::buffer(vData,vData.size()),boost::asio::transfer_all(),
[&writeResult, &ioError, &bytesWritten,
&ignoreTimeout, &timer, transaction, this]
(const boost::system::error_code &cError,
std::size_t iBytesTransferred)
{
boost::lock_guard< boost::mutex >
guard(this->_transactionMutex);

if (transaction == this->_currentTransaction)
{
++(this->_currentTransaction);
writeResult = cError;
bytesWritten = iBytesTransferred;
ioError = cError.value() != 0;
ignoreTimeout = true;
timer.cancel();
}
});

ioService().reset();

boost::system::error_code ioEc;
while (ioService().run_one(ioEc))
if (ioError && !ignoreIoError)
{
... something went wrong during I/O, return with error code ...
}
else if (timeout && !ignoreTimeout)
{
... timeout occurred, return with timeout error code ...
}

... here everything should be fine ...
}


The usage of "while (ioService().run_one(ioEc))" was the result of
googling around, and that's my doubt.

What I was trying to implement is:

a) block my thread, waiting for only ONE of the two handlers to complete
b) when one of the two handlers completes, I'd like to destroy the other
handler, i.e. I don't mind if it completes or not,
but I don't want to be notified of it

My first version called ioService().run_one(ioEc) without any while
loop, and had no mutex-protected _currentTransaction member.
What happened is that, even if I call ioService().reset(), when
performing read after write, all past handlers are processed,
accessing to references of variables that no longer exist.

I solved my problem using a transaction number, that is "frozen" in both
handlers at invocation, due to pass-by-value during
capture. When one of the handlers get called, increments the transaction
number, so if in future past handlers are called, they
go out quickly without any damages.

Are there any better solutions? This is my first attempt with Boost
Asio, probably I misunderstood some of its basic principles :(

Thanks a lot,
Antonio.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,954
Messages
2,570,116
Members
46,704
Latest member
BernadineF

Latest Threads

Top