Обратные вызовы в C++ | страница 90
6.2.6. Асинхронные запросы
Для реализации асинхронных запросов объявляется очередь, в которую помещаются все поступающие запросы. Обработка очереди происходит в отдельном потоке. Поток извлекает очередной запрос и для него выполняет обратный вызов. Объявление класса для выполнения асинхронных вызовов приведено в Листинг 93.
>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
> 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.
>void CommandQueue::readCommand()
>{
> while (!exit_) // (1)
> {
> std::unique_lock
> 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)