Виталий Евгеньевич Ткаченко

Обратные вызовы в C++


Скачать книгу

в котором какой-либо исполняемый код как аргумент передается в другой код, при этом ожидается, что через сохраненный аргумент исполняемый код будет запущен в нужный момент времени. Основные классы задач, решаемые с помощью обратных вызовов, следующие: запрос данных; вычисления по запросу; перебор элементов; уведомления о событиях.

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

      В синхронных вызовах при вызове функции инициатора обратный вызов осуществляется до выхода из тела функции. В асинхронных вызовах вызов может быть выполнен в любое время.

      Обратные вызовы часто используются в системных и C++ API. При использовании в системных API на реализацию обратных вызовов накладываются ограничения.

      Рассмотрев общую концепцию, приступим к обзору способов реализации обратных вызовов.

      2. Реализация обратных вызовов

      2.1. Указатель на функцию

      2.1.1. Концепция

      Графическое изображение реализации обратного вызова с помощью указателя на функцию представлено на Рис. 10. Исполнитель реализован в виде глобальной функции, в качестве контекста могут выступать любые данные. При настройке указатель на функцию как аргумент и указатель на данные как контекст сохраняются в инициаторе. Инициатор осуществляет обратный вызов посредством вызова функции через сохраненный указатель, передавая ей требуемые значения и контекст – указатель на данные. Поскольку инициатор не интерпретирует контекст и не выполняет с ним никаких операций, для хранения контекста используется нетипизированный указатель.

      Рис. 10. Обратный вызов с указателем на функцию

      2.1.2. Инициатор

      Реализация инициатора представлена в Листинг 12.

      Листинг 1.Иинициатор с указателем на функцию

      typedef void(*ptr_callback) (int eventID, void* pContextData);  // (1)

      ptr_callback ptrCallback = NULL;    // (2)

      void* contextData = NULL;           // (3)

      void setup(ptr_callback pPtrCallback, void* pContextData)  // (4)

      {

         ptrCallback = ptrCallback;

         contextData = pContextData;

      }

      void run()  // (5)

      {

        int eventID = 0;

        //Some actions

        ptrCallback(eventID, contextData);  // (6)

      }

      В строке 1 объявлен тип – указатель на функцию, в строке 2 объявлена переменная этого типа, в строке 3 объявлен указатель на данные контекста. В строке 4 объявлена функция для настройки указателей, в которой инициализируются соответствующие переменные. В строке 5 объявлена функция запуска, внутри этой функции инициатор в строке 6 производит вызов функции по сохраненному указателю. Сигнатура функции, объявленная в строке 1, в качестве первого параметра принимает значение, которое передается инициатором, т. е. информацию вызова, а второй параметр – это контекст. Указанная сигнатура здесь только для примера; конечно же, в зависимости от поставленных задач количество параметров и их порядок может быть