Есть, например, этот код:
int main() {
boost::asio::io_service service;
auto work = boost::asio::make_work_guard(service);
boost::asio::ip::tcp::socket socket{ service };
boost::asio::io_service::strand strand{ service };
std::string address{ "192.168.1.13" };
std::string port{ "8002" };
boost::asio::streambuf input{512};
boost::asio::thread_pool pool(1);
boost::asio::post(pool, [&service]()
{
try {
service.run();
}
catch (...)
{
::std::cout << "Catch" << ::std::endl;
}
}
);
auto lambda = [&input](auto er, auto tr) {
if (!er) {
::std::cout << tr << ::std::endl;
::std::istream st{ &input };
::std::string target;
for (unsigned int i = 0; i < tr; ++i)
target += st.get();
}
else {
::std::cout << er.message() << ::std::endl;
}
};
socket.async_connect(
{
boost::asio::ip::make_address(address),
boost::lexical_cast<unsigned short>(port)
},
boost::asio::bind_executor(
strand,
[](auto& er) {
if (!er)
::std::cout << "Success" << ::std::endl;
else {
::std::cout << "Error" << ::std::endl;
}
}
)
);
boost::asio::async_read_until(
socket,
input,
"/r/n",
boost::asio::bind_executor(
strand,
lambda
)
);
boost::asio::async_read_until(
socket,
input,
"/r/n",
boost::asio::bind_executor(
strand,
lambda
)
);
work.reset();
pool.join();
service.stop();
return 0;
}
И вывод из asio:
@asio|1550142117.477501|0*1|thread_pool@00E2FB60.post
@asio|1550142117.477501|>1|
@asio|1550142117.535496|0*2|socket@00E2FC24.async_connect
@asio|1550142117.536498|0*3|socket@00E2FC24.async_receive
@asio|1550142117.536498|0*4|socket@00E2FC24.async_receive
@asio|1550142117.536498|>3|ec=system:10057,bytes_transferred=0
@asio|1550142117.536498|3*5|strand@00E46A68.dispatch
@asio|1550142117.536498|>5|
A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied
@asio|1550142117.537497|<5|
@asio|1550142117.537497|<3|
@asio|1550142117.537497|>4|ec=system:10057,bytes_transferred=0
@asio|1550142117.537497|4*6|strand@00E46A68.dispatch
@asio|1550142117.537497|>6|
A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied
@asio|1550142117.537497|<6|
@asio|1550142117.537497|<4|
@asio|1550142117.537497|>2|ec=system:0
@asio|1550142117.537497|2*7|strand@00E46A68.dispatch
@asio|1550142117.537497|>7|
Success
@asio|1550142117.537497|<7|
@asio|1550142117.537497|<2|
@asio|1550142127.536385|<1|
Вопрос: На каком основании async_read_until выполняется раньше async_connect и как мне это избежать? boost::asio::io_service::strand отказывается помогать.
Дополнение: Я нашел причину в документации Strand -
Note that in the following case:
async_op_1(..., s.wrap(a)); async_op_2(..., s.wrap(b)); the completion of the first async operation will perform s.dispatch(a), and the second will perform s.dispatch(b), but the order in which those are performed is unspecified. That is, you cannot state whether one happens-before the other. Therefore none of the above conditions are met and no ordering guarantee is made.
Но от это не легче.
Оставшийся вопрос: Как мне это избежать, не меняя вышестояющую последовательность, т.е. последовательно вызывать async_* команды и выполнять их только в той последовательности?
UDP: Путем углубленного анализа документации, что надо было делать с самого начала, я понял, что async_* функции имеют несколько этапов и их не следует вызывать в одном потоке. Но это не сказано для async_connect в сокете. Проблема опережения чтения также осталась неизвестной.
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости