Какой правильный шаблон использовать с asio ::async_read?

#c #c 11 #boost-asio

#c #c 11 #boost-asio

Вопрос:

У меня есть проект, который взаимодействует с удаленной системой с помощью Asio. Я инкапсулировал весь код Asio в класс, который открывает синхронное соединение в конструкторе, а затем предоставляет открытый метод, чтобы пользователь класса мог записывать через сокет. Эти методы выполняют синхронизацию asio::write , а затем вызывают asio::async_read .

Теперь моя проблема:

Время ответа от удаленной системы неизвестно, поэтому мне нужно сообщить пользователю, что он должен подождать. Я подумываю о том, чтобы сделать это с помощью конечного автомата, который инициализируется, когда пользователь выполняет a asio::write и обновляет его снова при обратном asio::async_read вызове . Это означает, что клиентскому коду придется перебирать флаг в течение неопределенного времени, пока он ожидает обратного вызова read, что кажется мне хрупким.

Существуют ли лучшие механизмы для уведомления вызывающего кода об измененном состоянии? Если клиентский код зацикливается, будет asio::async_read ли вызываться обратный вызов и обновляться флаг?

Комментарии:

1. Большинство пользовательских интерфейсов предоставляют какой-то цикл сообщений в фоновом режиме, который может обновлять пользовательский интерфейс, поэтому я бы отправил сообщение в этот цикл из обработчика обратного вызова asio::async_read .

2. Есть клиентский код, но нет пользовательского интерфейса. Обновленный вопрос.

3. Ну, требуется какой-то цикл в вашей клиентской программе. Если нет существующего цикла, который вы могли бы использовать, вы должны его создать. boost condition_variable может быть полезен для ожидания ответа. используйте timed_wait, если вы не уверены на 100%, что получите ответ.

4. Превратите это в ответ, и я приму его.

5. Можете ли вы подробнее рассказать о модели потоков? Есть ли другой поток, выполняющийся io_service , пока другой поток ожидает async_read завершения? Если существуют отдельные потоки, то использование std::future или поддержка Asio для future может обеспечить краткое и элегантное решение.

Ответ №1:

Используйте boost::condition_variable следующим образом:

 //globals
boost::mutex mut;
boost::condition_variable cond;
bool waitflag = false;
bool response_available = false;



// inside async_read callback
bool waited;
{
    boost::mutex::scoped_lock lock(mut);
    if ((waited = waitflag)) // check if client loop is waiting for us
        waitflag = false;
    response_available = true;// write also any additional data to be read by client here
}
if (waited)
    cond.notify_one(); // notify client



// inside client loop, use a short waiting time if the loop needs to perform other tasks simultaneously
{
    boost::mutex::scoped_lock lock(mut);
    if (!response_available) {
        waitflag = true; // signal that we are waiting for callback
        cond.timed_wait(lock, boost::posix_time::milliseconds(100));
    }
    if (response_available) { // check if data arrived
    }
}