Выбрать главу
Листинг 92. Объявление контейнера (SensorContainer.h)

namespace sensor

{

  class ISensor;

  class SensorContainer

  {

  public:

    void addSensor(SensorNumber number, SensorPointer sensor);  // (1)

    void deleteSensor(SensorNumber number);                     // (2)

    SensorPointer checkSensorExist(SensorNumber number);        // (3)

    SensorPointer findSensor(SensorNumber number);              // (4)

    template<typename CallbackIterate>

    void forEachSensor(CallbackIterate&& callback)  // (5)

    {

      for (auto item : container_)                // (6)

      {

        callback(item.first, item.second);

      }

    }

private:

    std::map<SensorNumber, SensorPointer> container_;  // (7)

  };

};

Хранилище объектов реализовано в виде двоичного дерева (строка 7). Ключом здесь выступает номер датчика, содержимым является указатель на класс управления датчиком. Методы для добавления и удаления указателей объявлены в строках 1 и 2.

Метод в строке 3 возвращает указатель на объект класса, если последний с заданным номером содержится в хранилище, в противном случае возвращается нулевой указатель. Метод в строке 4 возвращает указатель на объект класса для соответствующего номера; если объект отсутствует, то генерируется исключение.

Метод 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<Command> 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<std::mutex> 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)

    }