Обратные вызовы в C++ | страница 90



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)