io_service object working mechanism - boost

I am confused about io_services object working mechanism. My understanding is that there is a queue associates with io_service object, if any async invocation will add one item in the queue, when io_service.run_once is called ,one async invocation will run and dequeue from the queue. if the queue is empty the io_service.run_one will do nothing until new invocation is added. I organized some code form the boost example but It seems that my understanding is wrong.
#include <boost/asio/connect.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/system/system_error.hpp>
#include <boost/asio/write.hpp>
#include <cstdlib>
#include <iostream>
#include <string>
#include <boost/bind.hpp>
using boost::asio::deadline_timer;
using boost::asio::ip::tcp;
class client
{
public:
client()
: socket_(io_service_)
{
}
void connect_handler(const boost::system::error_code& error,boost::system::error_code *er)
{
std::cerr<<"connect handler"<<std::endl;
*er = error;
std::cerr<<error<<std::endl;
}
void connect(const std::string& host, const std::string& service)
{
tcp::resolver::query query(host, service);
tcp::resolver::iterator iter = tcp::resolver(io_service_).resolve(query);
std::cerr<<"connect start"<<std::endl;
boost::system::error_code ec = boost::asio::error::would_block;
boost::asio::async_connect(socket_, iter, bind(&client::connect_handler,this,_1,&ec));
do
{io_service_.run_one();
}while (ec == boost::asio::error::would_block);
//io_service_.reset(); // The write async will be stuck without this reset call.
std::cerr<<"connect done"<<std::endl;
if (ec || !socket_.is_open())
throw boost::system::system_error(
ec ? ec : boost::asio::error::operation_aborted);
}
void write_handler(const boost::system::error_code& error, std::size_t size,boost::system::error_code* er )
{
std::cerr<<"write handler "<<std::endl;
*er=error;
std::cerr<<error<<std::endl;
}
void write_line(const std::string& line)
{
std::cerr<<"write start"<<std::endl;
std::string data = line + "\n";
boost::system::error_code ec = boost::asio::error::would_block;
boost::asio::async_write(socket_, boost::asio::buffer(data), bind(&client::write_handler,this,_1,_2,&ec));
do
{
io_service_.run_one();
}while (ec == boost::asio::error::would_block);
std::cerr<<"write done";
if (ec)
throw boost::system::system_error(ec);
}
private:
boost::asio::io_service io_service_;
tcp::socket socket_;
};
int main()
{
try
{
client c,d;
c.connect("172.217.6.36", "80");// google IP.
c.write_line("example");
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}
My understand is that:
Start
|
async_connect ----> add one item in io_service queue
|
|
io_serivce.run_one() ------> dequeue the async_connect call back from io_serivce queue
|
|
connect_handler --------> connect_handler called change the ec value
|
|
async_write ----------> add one item in io_service queue.
|
|
io_service.run_one()------------>dequeue the async_write call back from io_serivce queue
|
|
write_handler()----------------->write handler called and change the ec value
|
Done
but the reality is
Start
|
async_connect ----> add one item in io_service queue
|
|
io_serivce.run_one() ------> dequeue the async_connect call back from io_serivce queue
|
|
connect_handler --------> connect_handler called change the ec value
|
|
async_write ----------> add one item in io_service queue.
|
|
io_service.run_one()------------>stuck here in the while loop forever, the async_write handler is never be called the ec is never be changed.
Sehe told me that the io_service.reset needed to be called in another post, what I don't understand why io_service.reset needs to be called? the original example doesn't use this call and it works fine. With the reset call works:
Start
|
async_connect ----> add one item in io_service queue
|
|
io_serivce.run_one() ------> dequeue the async_connect call back from io_serivce queue
|
|
connect_handler --------> connect_handler called change the ec value
|
|
io_service.reset() --------> reset the io service.
|
|
async_write ----------> add one item in io_service queue.
|
|
io_service.run_one()------------>dequeue the async_write call back from io_serivce queue
|
|
write_handler()----------------->write handler called and change the ec value
|
Done

The original sample uses the deadline-timer which is in a continuous chain of async_waits. This means that the io_service will never run out of work.
That's it. The whole difference. If you let the service run out of work, run_* will return and you will need to call reset() before you can use the io_service again.
See also Why must io_service::reset() be called?
For context the earlier answer boost socket example stuck in while loop where I give several better approaches to making this work either using synchronous calls or using asynchronous calls.

Related

I2C not reading

I'm trying to interface with a BNO055 breakout board from a Teensy 2.0, but I'm having trouble reading from the BNO055. It has different registers that you can access to read data from the chip. To start, I'm just trying to read the IDs of some internal parts. No matter what I do, I seem to only get the last value that I put in TWDR. Trying to do a read doesn't seem to populate it. This is what I have in my main:
void main(void) {
CPU_PRESCALE(CPU_16MHz);
init_sensor();
char buffer[50];
sprintf(buffer, "Chip ID: %X\n", read_address(0x00));
while(1) {
_delay_ms(20);
}
}
This is my BNO055.c:
#include "BNO055.h"
#include <avr/io.h>
// The breakout board pulls COM3_state low internally
#define DEVICE_ADDR 0x29
#define READ 0
#define WRITE 1
#define F_CPU 16000000UL
#define SCL_CLOCK 400000L
inline void start(void) {
TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN);
while ( !(TWCR & (1<<TWINT)));
}
inline void stop(void) {
TWCR = (1 << TWINT) | (1 << TWSTO) | (1 << TWEN);
while(TWCR & (1 << TWSTO));
}
void send_address(uint8_t w) {
TWDR = (DEVICE_ADDR<<1) | w ;
TWCR = (1 << TWINT) | (1<<TWEN);
while(!(TWCR & (1 << TWINT)));
}
uint8_t read(void) {
TWCR = (1 << TWINT) | (1 << TWEN);
while(!(TWCR & (1 << TWINT)));
return TWDR;
}
void write(uint8_t data) {
TWDR = data;
TWCR = (1 << TWINT) | (1<<TWEN);
while(!(TWCR & (1 << TWINT)));
}
uint8_t read_address(uint8_t addr) {
start();
send_address(WRITE);
write(addr);
stop();
start();
send_address(READ);
const uint8_t value = read();
stop();
return value;
}
void write_address(uint8_t addr, uint8_t value) {
start();
send_address(WRITE);
write(addr);
write(value);
stop();
}
uint8_t status(void) {
return TWSR & 0xF8;
}
void init_sensor(void) {
// Setup I2C
DDRD &= ~((1 << 0) | (1 << 1));
PORTD |= ((1 << 0) | (1 << 1));
TWBR = ((( F_CPU / SCL_CLOCK ) - 16) / 2);
TWSR = 0;
TWCR = ((1 << TWEN) | (1 << TWIE) | (1 << TWEA));
}
This answer was written before the code in the question was updated in line with this answer. Not knowing this would confuse you as to how/why this answer(s|ed) the question.
The basic problem you're having is that you're issuing I2C start conditions and I2C stop conditions in places where they don't belong. The START an STOP conditions go at the beginning and end of an entire I2C transaction and not around each individual byte.
The data portion of a transaction is always entirely composed of data to be read or entirely composed of data to be written. So, performing a read of a register of a typical I2C device requires two I2C transactions. One involving writing the register address and the next involving reading the register's data, looking something like the following:
[I2C-START] [WRITE(I2C-DEVICE-WRITING-ADDRESS)] [WRITE(REGISTER-ADDRESS)] [I2C-STOP]
The write-transaction were we inform the I2C device of the register we want to read data from.
[I2C-START] [WRITE(I2C-DEVICE-READING-ADDESS)] [READ(REGISTER-DATA)] [I2C-STOP]
The read-transaction that conveys the data itself.
Potentially the last stop of the first could/should be omitted to create a I2C "repeated start" (which you probably don't need). So as not to confuse matters, I'm just going to go with the above scheme.
What you have, currently, looks more like this instead:
[I2C-START] [WRITE(I2C-DEVICE-WRITING-ADDRESS)] [I2C-STOP]
You've an empty write transaction.
[I2C-START] [WRITE(REGISTER-ADDRESS)] [I2C-STOP]
Now a transaction that tries to use a device register address as an I2C bus address
[I2C-START] [WRITE(I2C-DEVICE-READING-ADDRESS)] [I2C-STOP]
You've started a read transaction but didn't read any of the data that would follow if you issued a READ.
[I2C-START] [READ(?)] [I2C-STOP]
An attempt to read when you're supposed to writing either a I2C address (for either a read or write transaction).
The latter one is probably where you're getting in the most trouble and why you're seeing an unchanged TWDR; as an I2C master, you're never going to read a byte immediately following the start condition like that, since there's always supposed a byte written there containing address bits.
Put in terms of your code, you'd want something like:
uint8_t read_address(uint8_t addr) {
// The first transaction
// that tell the I2C device
// what register-address we want to read
start();
send_address(WRITE);
write(addr);
stop();
// The read transaction to get the data
// at the register address
// given in the prior transaction.
start();
send_address(READ);
const uint8_t r = read();
stop();
return r;
}
... where none of send_address(), write(), and read() contain any calls to either start() or stop().
I did test the above code, though not on a ATMega32U4; I used a different AVR that has the same TWI peripheral though and I do not have your I2C device.
Moving the start() and stop() into correct places did bring things from non-functional to functional in my test rig. So, when I say "something like" the above code,
I mean a lot like that. =) There may yet be other bugs, but this is the principal problem.

Sending method as callback function to field object in Rust

I want to implement a Timer object, which is owned by Foo object and it should call the Foo object's method periodically. I just implemented adding callback function (which is executing Foo object's method) to the Timer as below, but it failed to compile due to conflicting lifetime requirements.
Code (does not containing executing callback function part)
use std::sync::Mutex;
#[derive(Default)]
struct Timer<'a> {
callbacks: Mutex<Vec<Box<dyn Fn() + 'a>>>,
}
impl<'a> Timer<'a> {
fn add(&self, callback: Box<dyn Fn() + 'a>) {
let mut callbacks = self.callbacks.lock().unwrap();
callbacks.push(callback);
}
}
#[derive(Default)]
struct Foo<'a> {
value: usize,
timer: Timer<'a>,
}
impl<'a> Foo<'a> {
fn callback(&self) {
println!("value is {}", self.value);
}
fn process(&self) {
let callback = || {
self.callback();
};
self.timer.add(Box::new(callback));
}
}
fn main() {
let foo = Foo::default();
foo.process();
}
failed to compile with below error
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:28:24
|
28 | let callback = || {
| ________________________^
29 | | self.callback();
30 | | };
| |_________^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 27:5...
--> src/main.rs:27:5
|
27 | fn process(&self) {
| ^^^^^^^^^^^^^^^^^
note: ...so that the types are compatible
--> src/main.rs:28:24
|
28 | let callback = || {
| ________________________^
29 | | self.callback();
30 | | };
| |_________^
= note: expected `(&&Foo<'a>,)`
found `(&&Foo<'a>,)`
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 22:6...
--> src/main.rs:22:6
|
22 | impl<'a> Foo<'a> {
| ^^
note: ...so that the types are compatible
--> src/main.rs:32:20
|
32 | self.timer.add(Box::new(callback));
| ^^^
= note: expected `&Timer<'_>`
found `&Timer<'a>`
error: aborting due to previous error
I think the error comes from the process method in Foo object takes self as &'_ lifetime, but self.timer need &'a lifetime.
When I added &'a lifetime to self in process and callback method as below,
...
impl<'a> Foo<'a> {
fn callback(&'a self) {
...
}
fn process(&'a self) {
...
}
}
...
Below error occured-
error[E0597]: `self` does not live long enough
--> src/main.rs:29:13
|
22 | impl<'a> Foo<'a> {
| -- lifetime `'a` defined here
...
28 | let callback = || {
| -- value captured here
29 | self.callback();
| ^^^^ borrowed value does not live long enough
...
32 | self.timer.add(Box::new(callback));
| ------------------ cast requires that `self` is borrowed for `'a`
33 | }
| - `self` dropped here while still borrowed
error[E0597]: `foo` does not live long enough
--> src/main.rs:39:5
|
39 | foo.process();
| ^^^ borrowed value does not live long enough
40 | }
| -
| |
| `foo` dropped here while still borrowed
| borrow might be used here, when `foo` is dropped and runs the destructor for type `Foo<'_>`
error: aborting due to 2 previous errors
How to solve this problem?
The problem here is that you want to create a reference back to Foo inside Timer, but if Foo gets moved or if the Timer gets moved out of Foo while Foo is destroyed, this reference would be invalid. One (naive) way to fix this would be to use a reference counter for value and avoid referencing Foo directly:
#[derive(Default)]
struct Foo<'a> {
value: Rc<usize>,
timer: Timer<'a>,
}
impl<'a> Foo<'a> {
fn process(&self) {
let value_rc = self.value.clone();
let callback = move || {
println!("value is {}", *value_rc);
};
self.timer.add(Box::new(callback));
}
}
This makes using value a bit more difficult and would have a runtime overhead in Rc (or Arc if multithreaded). A better solution would probably be to split the structs entirely and use the normal lifetime rules like this:
#[derive(Default)]
struct Foo {
value: usize,
}
impl Foo {
fn callback(&self) {
println!("value is {}", self.value);
}
}
fn main() {
let foo = Foo::default();
let timer = Timer::default();
let callback = || {
foo.callback();
};
timer.add(Box::new(callback));
}
This way, Rust will make sure that foo, timer and callback each live long enough, because of the order that they are created and destroyed in inside main().

Libevent, add or remove events dynamically without having to change the event loop

I'm facing a problem that may be a misunderstanding of what this sentence really means "An application just needs to call event_dispatch() and then add or remove events dynamically without having to change the event loop." or I can't find the right documentation of how to do it.
Well, the problem is that I think that I should be able to add events to the event loop after running it with event_dispatch() but I can't get it working. Here is the code:
#include <event2/event.h>
#include <event2/buffer.h>
#include <event2/bufferevent.h>
#include <stdio.h>
static int n_calls = 0;
static int n_calls2 = 0;
void cb_func(evutil_socket_t fd, short what, void *arg)
{
struct event *me = arg;
printf("cb_func called %d times so far.\n", ++n_calls);
if (n_calls > 100)
event_del(me);
}
void cb_func2(evutil_socket_t fd, short what, void *arg)
{
struct event *me = arg;
printf("cb_func2 called %d times so far.\n", ++n_calls2);
if (n_calls2 > 100)
event_del(me);
}
int main(int argc, char const *argv[])
{
struct event_base *base;
enum event_method_feature f;
base = event_base_new();
if (!base) {
puts("Couldn't get an event_base!");
} else {
printf("Using Libevent with backend method %s.",
event_base_get_method(base));
f = event_base_get_features(base);
if ((f & EV_FEATURE_ET))
printf(" Edge-triggered events are supported.");
if ((f & EV_FEATURE_O1))
printf(" O(1) event notification is supported.");
if ((f & EV_FEATURE_FDS))
printf(" All FD types are supported.");
puts("");
}
struct timeval one_sec = { 1, 0 };
struct timeval two_sec = { 2, 0 };
struct event *ev;
/* We're going to set up a repeating timer to get called called 100 times. */
ev = event_new(base, -1, EV_PERSIST, cb_func, NULL);
event_add(ev, &one_sec);
event_base_dispatch(base);
// This event (two_sec) is never fired if I add it after calling event_base_dispatch.
// If I add it before calling event_base_dispatch it works as the other event (one_sec) also does.
ev = event_new(base, -1, EV_PERSIST, cb_func2, NULL);
event_add(ev, &two_sec);
return 0;
}
I see it now... I don't know why but I was thinking that the event-loop started running in another thread or something like that. I see now that what I was trying to do has no sense. You can add events inside the callbacks, that is, when the loop is running. When you start the event-loop, it never returns so everything after that will never be called (unless you stop the event-loop)

Callback passed to boost::asio::async_read_some never invoked in usage where boost::asio::read_some returns data

I have been working on implementing a half duplex serial driver by learning from a basic serial terminal example using boost::asio::basic_serial_port:
http://lists.boost.org/boost-users/att-41140/minicom.cpp
I need to read asynchronously but still detect when the handler is finished in the main thread so I pass async_read_some a callback with several additional reference parameters in a lambda function using boost:bind. The handler never gets invoked but if I replace the async_read_some function with the read_some function it returns data without an issue.
I believe I'm satisfying all of the necessary requirements for this function to invoke the handler because they are the same for the asio::read some function which returns:
The buffer stays in scope
One or more bytes is received by the serial device
The io service is running
The port is open and running at the correct baud rate
Does anyone know if I'm missing another assumption unique to the asynchronous read or if I'm not setting up the io_service correctly?
Here is an example of how I'm using the code with async_read_some (http://www.boost.org/doc/libs/1_56_0/doc/html/boost_asio/reference/basic_serial_port/async_read_some.html):
void readCallback(const boost::system::error_code& error, size_t bytes_transfered, bool & finished_reading, boost::system::error_code& error_report, size_t & bytes_read)
{
std::cout << "READ CALLBACK\n";
std::cout.flush();
error_report = error;
bytes_read = bytes_transfered;
finished_reading = true;
return;
}
int main()
{
int baud_rate = 115200;
std::string port_name = "/dev/ttyUSB0";
boost::asio::io_service io_service_;
boost::asio::serial_port serial_port_(io_service_,port_name);
serial_port_.set_option(boost::asio::serial_port_base::baud_rate(baud_rate));
boost::thread service_thread_;
service_thread = boost::thread(boost::bind(&boost::asio::io_service::run, &io_service_));
std::cout << "Starting byte read\n";
boost::system::error_code ec;
bool finished_reading = false;
size_t bytes_read;
int max_response_size = 8;
uint8_t read_buffer[max_response_size];
serial_port_.async_read_some(boost::asio::buffer(read_buffer, max_response_size),
boost::bind(readCallback,
boost::asio::placeholders::error,
boost::asio::placeholders::bytes_transferred,
finished_reading, ec, bytes_read));
std::cout << "Waiting for read to finish\n";
while (!finished_reading)
{
boost::this_thread::sleep(boost::posix_time::milliseconds(1));
}
std::cout << "Finished byte read: " << bytes_read << "\n";
for (int i = 0; i < bytes_read; ++i)
{
printf("0x%x ",read_buffer[i]);
}
}
The result is that the callback does not print out anything and the while !finished loop never finishes.
Here is how I use the blocking read_some function (boost.org/doc/libs/1_56_0/doc/html/boost_asio/reference/basic_serial_port/read_some.html):
int main()
{
int baud_rate = 115200;
std::string port_name = "/dev/ttyUSB0";
boost::asio::io_service io_service_;
boost::asio::serial_port serial_port_(io_service_,port_name);
serial_port_.set_option(boost::asio::serial_port_base::baud_rate(baud_rate));
boost::thread service_thread_;
service_thread = boost::thread(boost::bind(&boost::asio::io_service::run, &io_service_));
std::cout << "Starting byte read\n";
boost::system::error_code ec;
int max_response_size = 8;
uint8_t read_buffer[max_response_size];
int bytes_read = serial_port_.read_some(boost::asio::buffer(read_buffer, max_response_size),ec);
std::cout << "Finished byte read: " << bytes_read << "\n";
for (int i = 0; i < bytes_read; ++i)
{
printf("0x%x ",read_buffer[i]);
}
}
This version prints from 1 up to 8 characters that I send, blocking until at least one is sent.
The code does not guarantee that the io_service is running. io_service::run() will return when either:
All work has finished and there are no more handlers to be dispatched
The io_service has been stopped.
In this case, it is possible for the service_thread_ to be created and invoke io_service::run() before the serial_port::async_read_some() operation is initiated, adding work to the io_service. Thus, the service_thread_ could immediately return from io_service::run(). To resolve this, either:
Invoke io_service::run() after the asynchronous operation has been initiated.
Create a io_service::work object before starting the service_thread_. A work object prevents the io_service from running out of work.
This answer may provide some more insight into the behavior of io_service::run().
A few other things to note and to expand upon Igor's answer:
If a thread is not progressing in a meaningful way while waiting for an asynchronous operation to complete (i.e. spinning in a loop sleeping), then it may be worth examining if mixing synchronous behavior with asynchronous operations is the correct solution.
boost::bind() copies its arguments by value. To pass an argument by reference, wrap it with boost::ref() or boost::cref():
boost::bind(..., boost::ref(finished_reading), boost::ref(ec),
boost::ref(bytes_read));
Synchronization needs to be added to guarantee memory visibility of finished_reading in the main thread. For asynchronous operations, Boost.Asio will guarantee the appropriate memory barriers to ensure correct memory visibility (see this answer for more details). In this case, a memory barrier is required within the main thread to guarantee the main thread observes changes to finished_reading by other threads. Consider using either a Boost.Thread synchronization mechanism like boost::mutex, or Boost.Atomic's atomic objects or thread and signal fences.
Note that boost::bind copies its arguments. If you want to pass an argument by reference, wrap it with boost::ref (or std::ref):
boost::bind(readCallback, boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred, boost::ref(finished_reading), ec, bytes_read));
(However, strictly speaking, there's a race condition on the bool variable you pass to another thread. A better solution would be to use std::atomic_bool.)

Boost: Example needed: for timeout

I am already working long on this without success.
Imagine you have your main function some sort like this:
bool running = true;
int i = 0;
//waitHandler();
while(running)
i++;
Now I would like to add and call a timer, which sets running to false,
when it expires.
void waitHandler(){
boost::asio::io_service timerService;
//create and bind the timer
boost::asio::deadline_timer timer(timerService,
boost::posix_time::milliseconds(2000));
timer.wait();
running = true;
cout<<"WaitHandler triggered"<<endl;
}
Of course this does not work (when u uncomment the comment above),
since the timer will block the main thread.
What to do, if I would want to have this functionality without blocking the main function.
EDIT:
//transfer some error message
void set_result(boost::system::error_code* a, boost::system::error_code b,deadline_timer &timer)
{
a->assign(b.value(),b.category());
}
template<class SOCKET>
void read_with_timeout(SOCKET & sock, unsigned int delay,
const asio::mutable_buffers_1& buffers)
{
//create error messages
boost::system::error_code timer_result;
boost::system::error_code read_result;
//initialize timer
deadline_timer timer(sock.get_io_service());
timer.expires_from_now(boost::posix_time::milliseconds(delay));
timer.async_wait(boost::bind(set_result, &timer_result, _1,boost::ref(timer)));
//initialize receive mechanism
sock.async_receive(buffers, boost::bind(set_result, &read_result, _1,boost::ref(timer)));
sock.get_io_service().reset();
//should run for one handler
while (sock.get_io_service().run_one())
{
if (read_result.value()==0){ //zero stands for, that the message was received properly.
timer.cancel();
//cout<<"Message received: => Timer cancelled => RETURN!"<<endl;
return;
}
if(timer.expires_from_now().total_milliseconds() <=0){
sock.cancel();
//cout<<"Timeout => Socket cancelled => RETURN!"<<endl;
return;
}
}
}
As said this almost shows the wished behavior, but there are some questions to it:
Why by even using run_one, both the handler for the timer and the one for the receive can be fired
Why does receive also fire, when 0 bytes are received. For me that sounds like nothing is received and the function is supposed to wait?
Is this the right way to do it - as I said I want to receive or timeout. (like pinging)
Actually the pakets are received in wrong order as they appeared in Wireshark - I guess it has something to do with async_receive, which does not really wait for a incoming message, but just takes what is in the buffer before the function call.
What to do?
You are making this much more complex than it needs to be. There are piles of questions on this site dealing with timeouts, and a fantastic example on the Boost.Asio website. The comment from the async_tcp_client example has an excellent ASCII diagram explaining this scenario
// This class manages socket timeouts by applying the concept of a deadline.
// Some asynchronous operations are given deadlines by which they must complete.
// Deadlines are enforced by an "actor" that persists for the lifetime of the
// client object:
//
// +----------------+
// | |
// | check_deadline |<---+
// | | |
// +----------------+ | async_wait()
// | |
// +---------+
//
// If the deadline actor determines that the deadline has expired, the socket
// is closed and any outstanding operations are consequently cancelled.
//
// Connection establishment involves trying each endpoint in turn until a
// connection is successful, or the available endpoints are exhausted. If the
// deadline actor closes the socket, the connect actor is woken up and moves to
// the next endpoint.
//
// +---------------+
// | |
// | start_connect |<---+
// | | |
// +---------------+ |
// | |
// async_- | +----------------+
// connect() | | |
// +--->| handle_connect |
// | |
// +----------------+
// :
// Once a connection is :
// made, the connect :
// actor forks in two - :
// :
// an actor for reading : and an actor for
// inbound messages: : sending heartbeats:
// :
// +------------+ : +-------------+
// | |<- - - - -+- - - - ->| |
// | start_read | | start_write |<---+
// | |<---+ | | |
// +------------+ | +-------------+ | async_wait()
// | | | |
// async_- | +-------------+ async_- | +--------------+
// read_- | | | write() | | |
// until() +--->| handle_read | +--->| handle_write |
// | | | |
// +-------------+ +--------------+
//
// The input actor reads messages from the socket, where messages are delimited
// by the newline character. The deadline for a complete message is 30 seconds.
//
// The heartbeat actor sends a heartbeat (a message that consists of a single
// newline character) every 10 seconds. In this example, no deadline is applied
// message sending.
//
You should strive to achieve a similar design in your application. There is no need to bumble around by writing a read_with_timeout() function like you have posted in your question. Using async_read(), async_write(), and async_wait() will be enough to give you the desired functionality.
I think part of your confusion arises over threading. Don't think about it, understand the basic concepts first. You will want to use a single thread (the one invoking main()) and a single io_service to start. After that, you can explore more advanced concepts. If you're trying to integrate this code into a larger application, that is a different question entirely.
Studying the proactor design pattern may be helpful to you as well.
You can either execute io_service::run in a separate thread (and somehow synchronize the access to running) or pump the io_service loop manually within your while loop, using run_one()/poll()/poll_one() - whatever is appropriate in your case.
I have found out some sort of solution. I am ok with it even though there are things I do not understand.
//transfer some error message
void set_result(boost::system::error_code* a, boost::system::error_code b,deadline_timer &timer)
{
a->assign(b.value(),b.category());
}
template<class SOCKET>
void read_with_timeout(SOCKET & sock, unsigned int delay,
const asio::mutable_buffers_1& buffers)
{
//create error messages
boost::system::error_code timer_result;
boost::system::error_code read_result;
//initialize timer
deadline_timer timer(sock.get_io_service());
timer.expires_from_now(boost::posix_time::milliseconds(delay));
timer.async_wait(boost::bind(set_result, &timer_result, _1,boost::ref(timer)));
//initialize receive mechanism
sock.async_receive(buffers, boost::bind(set_result, &read_result, _1,boost::ref(timer)));
sock.get_io_service().reset();
//should run for one handler
while (sock.get_io_service().run_one())
{
if (read_result.value()==0){ //zero stands for, that the message was received properly.
timer.cancel();
//cout<<"Message received: => Timer cancelled => RETURN!"<<endl;
return;
}
if(timer.expires_from_now().total_milliseconds() <=0){
sock.cancel();
//cout<<"Timeout => Socket cancelled => RETURN!"<<endl;
return;
}
}
}
This actually works for my case and was taken from http://lists.boost.org/Archives/boost/2007/04/120339.php
referenced by this thread: How to set a timeout on blocking sockets in boost asio?
I just adapted it to Boost 1.51.
A few things are still obscured to me like e.g.
io_service.run_one actually still fires more event handlers even though it is supposed to only fire one.
Also there are events from the timer which do not at all interest me. I just want to catch the timeout and not other stuff. (I don know why there is other stuff)
In any case my problem was solved so far.
You have to spawn the timer on its own thread and then make sure that you protect the running variable from concurrent access.

Resources