#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
}
}