Look at Asio's file descriptor service objects.
Posix has a 'reactor' style asynchrony, so you don't actually need threads to achieve asynchronicity.
My example shows a reading loop that exits when 'exit' is typed /or/ when a timeout expires (10s).
#include <boost/asio.hpp>
#include <boost/asio/posix/stream_descriptor.hpp>
boost::asio::io_service my_io_service;
boost::asio::posix::stream_descriptor in(my_io_service, ::dup(STDIN_FILENO));
boost::asio::deadline_timer timer(my_io_service);
// handle timeout
void timeout_expired(boost::system::error_code ec) {
if (!ec)
std::cerr << "Timeout expired\n";
else if (ec == boost::asio::error::operation_aborted) // this error is reported on timer.cancel()
std::cerr << "Leaving early :)\n";
else
std::cerr << "Exiting for another reason: " << ec.message() << "\n";
// stop the reading loop
in.cancel();
in.close();
}
// set timeout timer
void arm_timeout()
{
timer.expires_from_now(boost::posix_time::seconds(10));
timer.async_wait(timeout_expired);
}
// perform reading loop
void reading_loop()
{
std::cerr << "(continueing input...)\n";
static boost::asio::streambuf buffer; // todo some encapsulation :)
async_read_until(in, buffer, '\n', [&](boost::system::error_code ec, size_t bytes_transferred) {
if (!ec)
{
std::string line;
std::istream is(&buffer);
if (std::getline(is, line) && line == "exit")
ec = boost::asio::error::operation_aborted;
else
reading_loop(); // continue
}
if (ec)
{
std::cerr << "Exiting due to: " << ec.message() << "\n";
// in this case, we don't want to wait until the timeout expires
timer.cancel();
}
});
}
int main() {
arm_timeout();
reading_loop();
my_io_service.run();
}
On windows, you can use the equivalent Windows Stream Handle
You could trivially add threads by running my_io_service.run()
on more than one thread.