|
Boost Users : |
Subject: Re: [Boost-users] boost::asio blocking socket read with timeout with multiple threads
From: Richard Hodges (hodges.r_at_[hidden])
Date: 2018-03-23 09:14:35
forgive me. I read "a synchronous call" as "asynchronous call".
Of course the correct way to "cancel" a sync call in linux is to raise a
signal, which should cause the socket's read to return with EINTR.
But before I realised my mistake, I wrote this little test to prove that
async calls are canclled :) Maybe someone will find it useful...
#include <cstdlib>
#include <sys/types.h>
#include <sys/wait.h>
#include <iostream>
#include <string>
#include <boost/asio.hpp>
using namespace std::literals;
namespace asio = boost::asio;
using protocol = asio::ip::tcp;
void server(protocol::acceptor& acceptor, int child_pid)
{
acceptor.listen();
auto& executor = acceptor.get_io_context();
auto sock = protocol::socket(executor);
auto timer = asio::system_timer(executor);
acceptor.accept(sock);
auto read_handler = [](auto ec, auto...)
{
if (ec)
std::cerr << "read handler error: " << ec.message();
else
std::cerr << "strange - we expected an error";
};
auto timer_handler = [&](auto ec)
{
if (not ec) {
sock.cancel();
}
};
sock.async_read_some(asio::null_buffers(), read_handler);
timer.expires_after(1s);
timer.async_wait(timer_handler);
executor.run();
auto data = "foo"s;
sock.write_some(asio::buffer(data));
int status = 0;
waitpid(child_pid, & status, 0);
}
void client(asio::io_context& executor, protocol::endpoint server_endpoint)
{
protocol::socket sock(executor);
sock.connect(server_endpoint);
auto on_read = [](auto, auto) {};
sock.async_read_some(asio::null_buffers(), on_read);
executor.run();
}
int main() {
auto executor = asio::io_context();
auto acceptor = protocol::acceptor(executor);
acceptor.open(protocol::v4());
acceptor.bind(protocol::endpoint(protocol::v4(), 0));
auto server_endpoint = acceptor.local_endpoint();
executor.notify_fork(asio::io_context::fork_prepare);
int child_pid = fork();
if (child_pid < 0)
{
std::cerr << "fork failed" << std::endl;
std::exit(100);
}
else if (child_pid > 0)
{
executor.notify_fork(asio::io_context::fork_parent);
server(acceptor,child_pid);
}
else
{
executor.notify_fork(asio::io_context::fork_child);
client(executor, server_endpoint);
}
return 0;
}
expected output:
> *read handler error: Operation canceled*
On 23 March 2018 at 08:44, Thomas Quarendon via Boost-users <
boost-users_at_[hidden]> wrote:
> > This seems unlikely. I have been using asio in production code on Linux
> for
> > 4 years. Can you post a mcve so I can test?
> Yes, the code I started this thread with:
> https://gist.github.com/tomq42/331b8d48110c5025e0fce93e689bd5a3
>
> I don't think this is a surprise. As far as I understand it, "cancel"
> isn't expected to cancel a *synchronous* read from the socket. It's more of
> a surprise to me that calling close on the socket doesn't have the effect
> of causing the read to return with an error. Both of these things work on
> Windows, and I started out on Windows, so the code was all fine there.
> _______________________________________________
> Boost-users mailing list
> Boost-users_at_[hidden]
> https://lists.boost.org/mailman/listinfo.cgi/boost-users
>
Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net