Boost Asio. Очередь обработчиков

129
07 октября 2019, 04:00

Есть, например, этот код:

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 в сокете. Проблема опережения чтения также осталась неизвестной.

READ ALSO
Маппинг аргументов командной строки JAVA

Маппинг аргументов командной строки JAVA

Есть некий framework, в котором парсится командная срокаСтрока имеет вид: --file=simple

116
Spring Test No qualifying bean of type с использование JavaConfig

Spring Test No qualifying bean of type с использование JavaConfig

недавно начал пользоваться JavaConfig в SpringИ сейчас решил попировать провести тесты, без использования xml

111
Сериализация java

Сериализация java

Есть задача: Необходимо написать класс который сериализует/десериализует Java BeansВ случае наличия циклических ссылок выкинуть exception

127
Регулярные выражения содержащие ()

Регулярные выражения содержащие ()

Возник вопросНеобходимо разобрать строку

135