Асинхронное уведомление
QHB предлагает асинхронное уведомление посредством команд LISTEN
и NOTIFY
. Сеанс клиента регистрирует свою заинтересованность в конкретном канале
уведомлений с помощью команды LISTEN
(и может остановить прослушивание с помощью
команды UNLISTEN
). Все сеансы, прослушивающие конкретный канал, будут уведомляться
асинхронно, когда в рамках любого сеанса выполняется команда NOTIFY
с именем
этого канала. Для передачи прослушивающим процессам дополнительных данных может
передаваться строка «полезные данные».
Приложения с libpq отправляют команды LISTEN
, UNLISTEN
и NOTIFY
как обычные
команды SQL. Поступление сообщений от команды NOTIFY
впоследствии можно отследить,
вызвав функцию PQnotifies.
Функция PQnotifies возвращает следующее уведомление из списка необработанных уведомительных сообщений, полученных от сервера. Она возвращает пустой указатель, если уведомления, ожидающие обработки, отсутствуют. Как только уведомление возвращается из PQnotifies, оно считается обработанным и будет удалено из списка уведомлений.
PGnotify *PQnotifies(PGconn *conn);
typedef struct pgNotify
{
char *relname; /* имя канала уведомлений */
int be_pid; /* PID серверного процесса, передающего уведомление */
char *extra; /* строка полезных данных уведомления */
} PGnotify;
После обработки объекта PGnotify, возвращенного функцией PQnotifies, обязательно освободите занимаемую им память с помощью функции PQfreemem. Достаточно освободить указатель на PGnotify; поля relname и extra не представляют отдельных областей памяти. (Эти поля названы так по историческим причинам; в частности, имена каналов не обязаны иметь какое-либо отношение к именам отношений.)
В Примере 2 представлен образец программы, иллюстрирующей применение асинхронного уведомления.
На самом деле функция PQnotifies не читает данные с сервера; она просто
возвращает сообщения, ранее собранные другой функцией libpq. В ранних выпусках
libpq единственным способом обеспечить своевременное получение сообщений от команды
NOTIFY
была постоянная отправка команд, пусть даже пустых, с последующей проверкой
PQnotifies после каждого вызова функции PQexec. Хотя этот метод все еще
работает, он считается устаревшим из-за излишней траты вычислительной мощности.
Более продвинутым способом проверки наличия сообщений от NOTIFY
, когда у вас
нет полезных команд для выполнения, является вызов функции PQconsumeInput с
последующей проверкой PQnotifies. Вы можете использовать select(), чтобы
подождать прибытия данных от сервера, как следствие, тратя ресурсы центрального
процессора, только если имеются операции для выполнения. (Как получить номер
дескриптора для использования с select(), рассказывается в описании функции
PQsocket.) Обратите внимание, что это будет работать независимо от того,
отправляете ли вы команды с помощью функции PQsendQuery/PQgetResult или
просто используете функцию PQexec. Однако нужно не забывать проверять
PQnotifies после каждого вызова PQgetResult или PQexec, чтобы увидеть, не
поступили ли во время обработки команды какие-либо уведомления.