Can I have blocking I/O within an asynchronous io_machine?
I have a server that's currently using asynchronous IO to (1) accept data from cin and send that input across a UNIX socket and (2) accept data on a UNIX socket, parse that data, and send back a response.
When I'm parsing the data, how can I block the I/O that occurs in the parser (ParseJSON(data_.data())
in the example below)? It should ask questions and collect answers to those questions via cin before returning parsed
for the async_write
; currently, the questions are printed, but the response is sent before the answers are input to cin.
socket_
is a stream_protocol::socket
from boost::asio
, FWIW.
void handle_read(const boost::system::error_code& error,
size_t bytes_transferred)
{
if (!error)
{
string parsed = ParseJSON(data_.data());
async_write(socket_,
buffer(parsed),
boost::bind(&session::handle_write,
shared_from_this(),
placeholders::error));
}
}
void handle_write(const boost::system::error_code& error)
{
if (!error)
{
socket_.async_read_some(buffer(data_),
boost::bind(&session::handle_read,
shared_from_this(),
placeholders::error,
placeholders::bytes_transferred));
}
}
An abbreviated version of what开发者_高级运维 happens in ParseJSON (Some strings replaced with <> for confidentiality):
string ParseJSON(string input)
{
int status;
string toWrite;
JSONNode parsed = libjson::parse(input);
JSONNode::const_iterator iter = parsed.begin();
json_string node_name = iter -> as_string();
if (node_name.compare("<>") == 0)
{
cout << "<>" << endl;
cout << "<>";
cout.flush();
cin >> status;
JSONNode n(JSON_NODE);
n.push_back(JSONNode("<>","<>"));
JSONNode c(JSON_NODE);
c.set_name("args");
c.push_back(JSONNode("<>",status));
n.push_back(c);
toWrite = n.write();
return toWrite;
}
}
If ParseJSON()
does a blocking read from cin
then it will block which means that handle_read()
won't execute the async_write()
until ParseJSON()
returns.
I think the problem is that parsed
is a stack variable. handle_read()
will most likely return before the data is actually written and parsed
will be destroyed. The data passed to async_write()
needs to be valid until the completion handler (handle_write
) is called.
If handle_read()
and and handle_write()
are member functions you could add a parsed
member to hold the data. Alternatively, you could wrap parsed
in shared_ptr that is bound to handle_write()
something like this:
void handle_read(const boost::system::error_code& error,
size_t bytes_transferred)
{
if (!error)
{
string *ps = new string(ParseJSON(data_.data()));
boost::shared_ptr<string> pParsed(ps);
async_write(socket_,
buffer(*pParsed),
boost::bind(&session::handle_write,
shared_from_this(),
pParsed,
placeholders::error));
}
}
void handle_write(boost::shared_ptr<string> pParsed,
const boost::system::error_code& error)
{
if (!error)
{
socket_.async_read_some(buffer(data_),
boost::bind(&session::handle_read,
shared_from_this(),
placeholders::error,
placeholders::bytes_transferred));
}
}
When the completion handler exits, the last reference to the shared_ptr will disappear and ps
will be destroyed.
精彩评论