Управление буферами
Выделение памяти под буферы
Некоторые объекты, такие как объект sock. или объект ser., используют буферы для хранения отправляемых и принимаемых данных. Например, у каждого последовательного порта объекта ser. два буфера - приёма (RX) и передачи (TX), а у каждого сокета объекта sock. не менее шести разных буферов.
По умолчанию память под буферы не выделена, а это, по сути, означает, что они не могут хранить данные. Чтобы связанные объекты работали, буферам нужно выделить память.
Память выделяется страницами по 256 байт. На каждый буфер приходится небольшой служебный объём - 17 байт для 16-разрядных платформ и 33 байта для 32-разрядных, - используемый для внутреннего учёта буфера (переменные, указатели и т. п.). Поэтому если буферу выделено 2 страницы, его реальная ёмкость составит 2 * (256 - 17) = 494 байта.
Выделение памяти под буферы - двухэтапный процесс. Сначала вы запрашиваете определённое число страниц для каждого порта, сокета и т. п., которые собираетесь использовать. Это делается методами соответствующих объектов. Например, метод ser.rxbuffrq запрашивает память под буфер приёма (RX) одного из последовательных портов. Аналогичные методы есть для всех остальных буферов всех объектов, которым нужна память под буферы. Обратите внимание: на этом этапе память фактически не выделяется - собираются только ваши «запросы».
После того как все запросы сделаны, память фактически выделяется методом sys.buffalloc. Он выделяет память по предыдущим запросам для всех буферов всех объектов. Пример:
'allocate memory for RX and TX buffers of serial port 0 and socket 0
'make requests
ser.num= 0
ser.rxbuffrq= 5
ser.txbuffrq= 5
sock.num=0
sock.rxbuffrq= 4
sock.txbuffrq= 4
'and now actual allocation
sys.buffalloc
Обычно память под буферы выделяется в обработчике события on_sys_init, но это необязательно. Более того, приложение может перераспределять память буферов при смене режима работы или других условий.
Метод sys.buffalloc может выполняться до нескольких сотен миллисекунд, поэтому его имеет смысл использовать как можно реже. Сначала сделайте все необходимые запросы на выделение буферов, а затем один раз вызовите sys.buffalloc, чтобы завершить работу.
(Пере)выделение буфера для конкретного объекта сработает, только если соответствующий объект или та часть объекта, которой принадлежит буфер, простаивает. «Часть» - это, например, конкретный последовательный порт объекта ser. или конкретный сокет объекта sock., которому принадлежит изменяемый буфер. «Простаивает» для разных объектов означает разное: ser.enabled = 0 - NO для последовательного порта, sock.statesimple = 0 - PL_SSTS_CLOSED для сокета и т. д.
Разумное выделение памяти с учётом доступного объёма
Память - не бесконечный ресурс, и не всегда удастся получить столько, сколько вы запросили. Методы вроде ser.rxbuffrq фактически возвращают объём памяти, который можно выделить:
dim x as byte
x=ser.rxbuffrq(5) 'x could get less than 5, which means that you got less memory than you have asked for
Чтобы помочь разумно распределять память с учётом доступного объёма, в объекте sys. реализованы два свойства:
- Свойство sys.totalbuffpages (только чтение) сообщает, сколько всего страниц буферов доступно в системе. Это значение определяется объёмом физической памяти переменных (RAM) за вычетом памяти, нужной для хранения переменных проекта (поэтому по мере роста проекта память под буферы уменьшается).
- Свойство sys.freebuffpages (только чтение) сообщает число свободных (ещё не выделенных) страниц буферов.
Пример, в котором память поровну распределяется между буферами передачи (TX) и приёма (RX) четырёх последовательных портов и четырёх сокетов:
dim x,f as byte
x=sys.totalbuffpages/16 'will work correctly if we haven't allocated anything yet
for f=0 to 3
ser.num= f
ser.rxbuffrq(x)
ser.txbuffrq(x)
sock.num= f
sock.rxbuffrq(x)
sock.txbuffrq(x)
next f
В этом примере результаты запросов отдельных буферов не проверяются, поскольку размер каждого буфера уже рассчитан по общему числу доступных страниц буферов.