А. Григорьев - О чём не пишут в книгах по Delphi
- Название:О чём не пишут в книгах по Delphi
- Автор:
- Жанр:
- Издательство:БХВ-Петербург
- Год:2008
- Город:СПб
- ISBN:978-5-9775-019003
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
А. Григорьев - О чём не пишут в книгах по Delphi краткое содержание
Рассмотрены малоосвещённые вопросы программирования в Delphi. Описаны методы интеграции VCL и API. Показаны внутренние механизмы VCL и приведены примеры вмешательства в эти механизмы. Рассмотрено использование сокетов в Delphi: различные механизмы их работы, особенности для протоколов TCP и UDP и др. Большое внимание уделено разбору ситуаций возникновения ошибок и получения неверных результатов в "простом и правильном" коде. Отдельно рассмотрены особенности работы с целыми, вещественными и строковыми типами данных, а также приведены примеры неверных результатов, связанных с ошибками компилятора, VCL и др. Для каждой из таких ситуаций предложены методы решения проблемы. Подробно рассмотрен синтаксический анализ в Delphi на примере арифметических выражений. Многочисленные примеры составлены с учётом различных версий: от Delphi 3 до Delphi 2007. Прилагаемый компакт-диск содержит примеры из книги.
Для программистов
О чём не пишут в книгах по Delphi - читать онлайн бесплатно ознакомительный отрывок
Интервал:
Закладка:
2.2.7. Асинхронный режим, основанный на событиях
Асинхронный режим, основанный на событиях, появился во второй версии Windows Sockets. В его основе лежат события — специальные объекты, служащие для синхронизации работы нитей.
Существуют события, поддерживаемые на уровне системы. Они создаются с помощью функции CreateEvent
. Каждое событие может находиться в сброшенном или взведенном состоянии. Нить с помощью функций WaitForSingleObject
и WaitForMultipleObjects
может дожидаться, пока одно или несколько событий не окажутся во взведенном состоянии. В режиме ожидания нить не требует процессорного времени. Другая нить может установить событие с помощью функции SetEvent
, в результате чего первая нить выйдет из состояния ожидания и продолжит свою работу. Подробно о системных событиях и прочих объектах синхронизации написано в [2].
Аналогичные объекты определены и в Windows Sockets. Сокетные события отличаются от стандартных системных событий прежде всего тем, что они могут быть связаны с событиями FD_XXX
, происходящими на сокете, и взводиться при наступлении этих событий.
Так как сокетные события поддерживаются только в WinSock 2, модуль WinSock не содержит объявлений типов и функций, требуемых для их поддержки. Поэтому их придется объявлять самостоятельно. Прежде всего, должен быть объявлен тип дескриптора событий, который в MSDN называется WSAEVENT
. В Delphi он может быть объявлен следующим образом:
PWSAEvent = ^TWSAEvent;
TWSAEvent = THandle;
Событие создается с помощью функции WSACreateEvent
, прототип которой приведен в листинге 2.55.
WSACreateEvent
// ***** Описание на C++ *****
WSAEVENT WSACreateEvent(void);
// ***** Описание на Delphi *****
function WSACreateEvent: TWSAEvent;
Событие, созданное этой функцией, находится в сброшенном состоянии, при ожидании автоматически не сбрасывается, не имеет имени и обладает стандартными атрибутами безопасности. В MSDN отмечено, что сокетное событие на самом деле является простым системным событием, и его можно создавать с помощью стандартной функции CreateEvent
, управляя значениями всех перечисленных параметров.
Функция создает событие и возвращает его дескриптор. Если произошла ошибка, функция возвращает значение WSA_INVALID_EVENT
(0). Для ручного взведения и сброса события предназначены функции WSASetEvent
и WSAResetEvent
соответственно, прототипы которых приведены в листинге 2.56.
// ***** Описание на C++ *****
BOOL WSASetEvent(WSAEVENT hEvent);
BOOL WSAResetEvent(WSAEVENT hEvent);
// ***** Описание на Delphi *****
function WSASetEvent(hEvent: TWSAEvent): BOOL;
function WSAResetEvent(hEvent: TWSAEvent): BOOL;
Функции возвращают True
, если операция прошла успешно, и False
— в противном случае.
После завершения работы с событием оно уничтожается с помощью функции WSACloseEvent
(листинг 2.57).
WSACloseEvent
// ***** Описание на C++ *****
BOOL WSACloseEvent(WSAEVENT nEvent);
// ***** Описание на Delphi *****
function WSACloseEvent(hEvent: TWSAEvent): BOOL;
Функция уничтожает событие и освобождает связанные с ним ресурсы. Дескриптор, переданный в качестве параметра, становится недействительным. Для ожидания взведения событий служит функция WSAWaitForMultiрleEvents
(листинг 2.58).
WSAWaitForMultipleEvents
// ***** Описание на C++ *****
DWORD WSAWaitForMultipleEvents(DWORD cEvents, const WSAEVENT FAR *lphEvents, BOOL fWaitAll, WORD dwTimeout, BOOL fAlertable);
// ***** Описание на Delphi *****
function WSAWaitForMultipleEvents(cEvents: DWORD; lphEvents: PWSAEvent; fWaitAll: BOOL; dwTimeout: DWORD; fAlertable: BOOL): DWORD;
Дескрипторы событий, взведения которых ожидает нить, должны храниться в массиве, размер которого передаётся через параметр cEvents
, а указатель — через параметр lphEvents
. Параметр fWaitAll
определяет, что является условием окончания ожидания: если он равен True
, ожидание завершается, когда все события из переданного массива оказываются во взведенном состоянии, если False
— когда оказывается взведенным хотя бы одно из них. Параметр dwTimeout
определяет тайм-аут ожидания в миллисекундах. В WinSock 2 определена константа WSA_INFINITE
(совпадающая по значению со стандартно константой INFINITE
), которая задает бесконечное ожидание. Параметр fAlertable
нужен при перекрытом вводе-выводе: мы рассмотрим его позже в разд. 2.2.9 . Если перекрытый ввод-вывод не используется, fAlertable
должен быть равен False
.
Существует ограничение на число событий, которое можно ожидать с помощью данной функции. Максимальное число событий определяется константой WSA_MAXIMUM_WAIT_EVENTS
, которая в данной реализации равна 64.
Результат, возвращаемый функцией, позволяет определить, по каким причинам закончилось ожидание. Если ожидалось взведение всех событий ( fWaitAll = True
), и оно произошло, функция возвращает WSA_WAIT_EVENT_0
(0). Если ожидалось взведение хотя бы одного из событий, возвращается WSA_WAIT_EVENT_0 + Index
, где Index
— индекс взведенного события в массиве lphEvents
(отсчет индексов начинается с нуля). Если ожидание завершилось по тайм-ауту, возвращается значение WSA_WAIT_TIMEOUT
(258). И наконец, если произошла какая-либо ошибка, функция возвращает WSA_WAIT_FAILED
( $FFFFFFFF
).
Существует еще одно значение, которое может возвратить функция WSAWaitForMultipleEvents
: WAIT_IO_COMPLETION
(это константа из стандартной части Windows API, она объявлена в модуле Windows
). Смысл этого результата и условия, при которых он может быть возвращен, мы рассмотрим в разд. 2.2.9 .
Функции, которые мы рассматривали до сих пор, являются аналогами системных функций для стандартных событий. Теперь мы переходим к рассмотрению тех функций, которые отличают сокетные события от стандартных. Главная из них — WSAEventSelect
, позволяющая привязать события, создаваемые с помощью WSACreateEvent
, к тем событиям, которые происходят на сокете. Прототип этой функции приведен в листинге 2.59.
WSAEventSelect
// ***** Описание на C++ *****
int WSAEventSelect(SOCKET s, WSAEVENT hEventObject, long lNetworkEvents);
// ***** описание на Delphi *****
function WSAEventSelect(S: TSocket; hEventObject: TWSAEvent; lNetworkEvents: LongInt): Integer;
Эта функция очень похожа на функцию WSAAsyncSelect
, за исключением того, что события FD_XXX
привязываются не к оконным сообщениям, а к сокетным событиям. Параметр S
определяет сокет, события которого отслеживаются, параметр hEventObject
— событие, которое должно взводиться при наступлении отслеживаемых событий, lNetworkEvents
— комбинация констант FD_XXX
, определяющая, с какими событиями на сокете связывается событие hSocketEvent
.
Функция WSAEventSelect
возвращает ноль, если операция прошла успешно, и SOCKET_ERROR
при возникновении ошибки.
Интервал:
Закладка: