Различие между синхронными и асинхронными вызовами проиллюстрировано на Рис. 9. В первом случае поток управления входит в функцию
Рис. 9. Синхронные и асинхронные вызовы: а) синхронный; б) асинхронный
Особенностью реализации синхронных вызовов является то, что здесь не нужно хранить аргумент: он передается как параметр в функцию инициатора и используется только внутри этой функции. В случае асинхронных вызовов необходима предварительная настройка аргумента, который должен быть сохранен в какой-либо нелокальной переменной.
1.4.2. Использование вызовов в API
API (Application Programming interface, интерфейс прикладных программ) – это программный код, реализующий некоторую функциональность, а также объявления, через которые некоторая программа может вызывать этот код. Указанные объявления реализуют интерфейс API.
Интерфейс API – набор объявлений для вызова кода API.
При проектировании API должны соблюдаться следующие требования.
1.
2.
3.
С точки зрения C++ интерфейсы API могут быть разделены на два больших класса.
Системный API: интерфейс объявляется в виде набора функций, поддерживающих стандартный протокол вызова. Любая программа, независимо от того, на каком языке она написана, может обратиться к указанному API путем вызова функций интерфейса. Как правило, системные API реализуются в виде динамически разделяемых библиотек. В качестве примера можно назвать всем известный Windows API, реализация которого находится в системной библиотеке User32.dll. Любое приложение может загрузить эту библиотеку и вызывать требуемые функции для выполнения системных вызовов.
C++ API: интерфейс объявляется в виде набора классов C++. Как и системные, С++ API чаще всего реализуются в виде динамических библиотек, но могут поставляться также в виде статических. Использовать такие API могут только те программные компоненты, которые могут интерпретировать вызовы C++. Так, например, среда выполнения для языка Python может вызывать методы классов C++, а вот у Visual Basic такая возможность отсутствует.
Интерфейсы системных API должны объявляться в стиле языка C, т. е. в них должны использоваться функции с фиксированным числом параметров и простые структуры данных, такие, как числа, символы, указатели и структуры. Это связано с тем, что такие объявления следуют стандартным соглашениям операционной системы, в силу чего любая программа, независимо от используемого языка программирования (даже написанная на ассемблере), может использовать указанный API. Однако из-за требования описания интерфейсов в стиле C на реализацию обратных вызовов накладываются ограничения, которые будут рассматриваться в соответствующих главах.
1.5. Итоги
Обратный вызов – это паттерн, в котором какой-либо исполняемый код как аргумент передается в другой код, при этом ожидается, что через сохраненный аргумент исполняемый код будет запущен в нужный момент времени. Основные классы задач, решаемые с помощью обратных вызовов, следующие: запрос данных; вычисления по запросу; перебор элементов; уведомления о событиях.
Модель обратных вызовов включает в себя следующие понятия: исполнитель, инициатор, аргумент, настройка, контекст.
В синхронных вызовах при вызове функции инициатора обратный вызов осуществляется до выхода из тела функции. В асинхронных вызовах вызов может быть выполнен в любое время.
Обратные вызовы часто используются в системных и C++ API. При использовании в системных API на реализацию обратных вызовов накладываются ограничения.
Рассмотрев общую концепцию, приступим к обзору способов реализации обратных вызовов.
2. Реализация обратных вызовов
2.1. Указатель на функцию
2.1.1. Концепция