Метод 5 предназначен для итерации по всем хранимым объектам. Здесь используется обратный синхронный вызов (см. п. 1.4.1) по схеме «перебор элементов» (см. п. 1.2.3). Реализация осуществляет перебор всех элементов хранилища, для каждого элемента выполняется соответствующий вызов. Метод реализован в виде шаблона, что позволяет его использование для различных типов объектов. Входным параметром метода выступает объект вызова, объявленный как ссылка на r-value. Такое объявление позволяет передавать выражения или временные копии объектов.
6.2.6. Асинхронные запросы
Для реализации асинхронных запросов объявляется очередь, в которую помещаются все поступающие запросы. Обработка очереди происходит в отдельном потоке. Поток извлекает очередной запрос и для него выполняет обратный вызов. Объявление класса для выполнения асинхронных вызовов приведено в Листинг 93.
Листинг 93. Класс для выполнения асинхронных вызовов (CommandQueue.h)
class CommandQueue
{
public:
void start(); // (1)
void stop(); // (2)
void addCommand(SensorNumber number, SensorPointer pointer, SensorValueCallback callback); // (3)
private:
struct Command // (4)
{
SensorNumber number;
SensorPointer pointer;
SensorValueCallback callback;
};
std::queue commandQueue_ ; // (5)
std::condition_variable conditional_; // (6)
std::mutex mutex_; // (7)
std::thread queueThread_; // (8)
bool exit_; // (9)
void readCommand(); // (10)
};
В строке 4 объявлена структура, в которой будут храниться данные для выполнения вызова: номер датчика, указатель на класс датчика и объект вызова. В строке 5 объявлен контейнер, который будет хранить указанные структуры. В строках 6 и 7 объявлены переменные для синхронизации операций записи/чтения очереди, в строке 8 объявлен класс для запуска потока обработки очереди, в строке 9 объявлен индикатор для завершения работы потока.
В строке 1 объявлен метод, который запускает поток обработки очереди, в строке 2 объявлен метод для остановки этого потока. Метод, объявленный в строке 3, добавляет переданные данные в очередь путем создания экземпляра структуры 4 и размещения ее в контейнере 5.
Обработка очереди реализована в методе, объявленном в строке 10. Поток обработки очереди вызывает этот метод, который, в свою очередь, ожидает поступления записей и обрабатывает их. Реализация приведена в Листинг 95.
Листинг 94. Обработка очереди запросов (CommandQueue.cpp)
void CommandQueue::readCommand()
{
while (!exit_) // (1)
{
std::unique_lock lock(mutex_); // (2)
conditional_.wait(lock, [this]() {return commandQueue_.size() > 0 || exit_ == true; }); // (3)
while (commandQueue_.size() > 0 && exit_ == false) // (4)
{
Command cmd = commandQueue_.front(); // (5)
commandQueue_.pop(); // (6)
lock.unlock(); // (7)
cmd.callback(cmd.number, cmd.pointer->getValue()); // (8)
lock.lock(); // (9)
}
}
}
Пока не установлен индикатор завершения (устанавливается в методе stop), выполняется цикл 1. Вначале блокируется мьютекс 2 (это необходимо для корректной работы условной переменной), затем осуществляется ожидание условной переменной 3. Когда метод addCommandсформировал новую запись и добавил ее в контейнер, он инициирует срабатывание условной переменной, и поток выполнения переходит к циклу 4 (мьютекс при этом оказывается заблокирован). Этот цикл работает, пока очередь не опустеет либо будет установлен индикатор выхода.
В строке 5 из контейнера извлекается очередная запись, в строке 6 эта запись удаляется из контейнера. В строке 7 снимается блокировка мьютекса, что позволяет добавлять в контейнер новые записи, пока идет обработка очередной команды. В строке 8 осуществляется обратный вызов, в строке 9 мьютекс блокируется вновь, и далее повторяется цикл 4.
Объявление класса наблюдателя приведено в Листинг 95.
Листинг 95. Наблюдатель – класс для отслеживания пороговых значений (Observer.h)
class Observer
{
public:
void start(); // (1)
void stop(); // (2)
void addAlert(SensorNumber number, SensorPointer pointer, SensorAlertCallback callback, SensorValue alertValue, AlertRule alertRule, CheckAlertTimeout checkTimeoutSeс); // (3)
void deleteAlert(SensorNumber number); // (4)
private:
struct Alert // (5)
{
Alert() {}
Alert(SensorAlertCallback callback, SensorValue alertValue, AlertRule alertRule, SensorPointer sensor, CheckAlertTimeout checkTimeout):
callback(callback), alertValue(alertValue), alertRule(alertRule), sensor(sensor), checkTimeout(checkTimeout), currentTimeout(0)
{
}
SensorAlertCallback callback;
Читать дальше