Примитивы и механизм доступа


Содержание

Примитивы и механизм доступа

НЕКОТОРЫЕ ПОДХОДЫ К ОРГАНИЗАЦИИ СОДЕРЖАТЕЛЬНОГО ПОИСКА ИЗОБРАЖЕНИЙ И ВИДЕОИНФОРМАЦИИ

Авторы в этой статье приводит некоторые подходы в организации содержательного поиска изображений и видеоинформации

Н.С.Байгарова, Ю.А.Бухштаб, Н.Н.Евтеева, Д.А.Корягин

Введение

Предлагаемые подходы ориентированы на решение проблемы обеспечения доступа к современным электронным коллекциям изображений и видеоматериалов с использованием различных средств — как текстовых описаний, так и характеристик визуального содержания, простейших типа цветовой гаммы, и более сложных, связанных с распознаванием образов, наиболее интересных для предметной области.
До недавнегонего времени традиционным считался поиск визуальной информации, опирающийся на индексирование текстовых описаний, ассоциированных с изображением или фильмом. Однако поиск по названию, авторам, теме, словам описания содержания и по другой текстовой информации, ассоциированной с изображениями коллекции, представляется недостаточным. Неоднозначность соответствия между визуальным содержанием и текстовым описанием снижает показатели точности и полноты поиска.

Визуальные примитивы и механизм поиска по образцу

Для организации электронных библиотек, связанных с визуальными данными, требуются методы создания и использования поисковых образов, отражающих визуальное содержание изображений. Методы распознавания образов и понимания сцены в настоящее время из-за отсутствия эффективных универсальных алгоритмов применяются в узких предметных областях. Современная универсальная технология доступа к коллекциям изображений связана с сопоставлением изображению набора визуальных примитивов (характеристик цвета, формы, текстуры, а для видео еще и параметров движения сцены и объектов) и определением количественной оценки близости изображений по значениям примитивов.

Визуальные примитивы — это характеристики изображения, которые автоматически вычисляются по оцифрованным визуальным данным, позволяют эффективно индексировать их и обрабатывать запросы с использованием визуальных свойств изображения. Поисковый образ изображения, сгенерированный из визуальных примитивов, невелик по размеру в сравнении с самим изображением и удобен для организации поиска. Вычисление подобия изображений заменяет принятую в традиционных СУБД операцию установления соответствия запросу. Хотя запросом в такой системе может быть описание набора примитивов, более удобен запросный механизм поиска по образцу, когда система отыскивает изображения, визуально похожие на предоставленный образец. Система анализирует образец аналогично тому, как это делается при составлении поисковых образов изображений базы. Вычисление подобия изображения-образца изображениям коллекции осуществляется на основании сравнения значений отдельных визуальных примитивов, при этом система определяет меру их отличия, а затем сортирует изображения базы в соответствии с близостью к образцу по всем параметрам, с учетом указываемой в запросе степени важности каждого параметра. Поиск на таком уровне абстракции не предполагает идентификацию объектов. Скажем, если в качестве образца взято изображение собаки, то система будет искать изображения, похожие на образец по цветовой гамме, композиции, наличию определенных форм и т.п., но нет никакой гарантии, что среди них окажется изображение именно этого животного. Тем не менее, метод поиска по образцу на основании визуальных примитивов представляется на сегодняшний день достаточно эффективным и универсальным средством доступа к коллекциям оцифрованных изображений.

3. Методы анализа изображений

Различными группами исследователей уже накоплен определенный опыт реализации алгоритмов, позволяющих автоматически описывать изображения в терминах простых вычислимых визуальных свойств, а также определять меру их отличия. Авторами был подготовлен обзор этих алгоритмов [8].

Механизмы синхронизации

Читайте также:

  1. Ая группа. Механизмы организации дыхательного акта
  2. Базисные механизмы надежности
  3. Биологические механизмы половой дифференциации
  4. В процессе эволюции сформировались мощные гомеостатические механизмы, обеспечивающие нормальное снабжение тканей кислородом и удаление из них углекислого газа
  5. В процессе эволюции сформировались мощные гомеостатические механизмы, обеспечивающие нормальное снабжение тканей кислородом и удаление из них углекислого газа
  6. Вибрационные механизмы
  7. Виды и механизмы разрушения.
  8. Вина и стыд как механизмы, социального контроля
  9. Возможные механизмы разрушения полимеров в зависимости от температуры
  10. Воображение, его формы и механизмы
  11. Главные цели, принципы, механизмы и инструменты планирования на предприятии
  12. Гомеостаз глюкозыподдерживают следующие механизмы.

Межпроцессное взаимодействие (IPC, interprocess communication) разбивается на три пункта:

— передача информации от одного процесса другому;

— контроль над деятельностью процессов (процессы не должны пересекаться в критических ситуациях);

— согласование действий процессов (например, если процесс А поставляет данные, а процесс В выводит их на печать, то процесс В должен не начинать печатать, пока не поступят данные от процесса А).

В ряде операционных систем процессы, работающие совместно, могут сообща использовать общее хранилище данных (считывать данные и записывать информацию) – участок в основной памяти или файл общего доступа. Например, если процессу требуется вывести на печать файл, он помещает имя файла в специальный каталог спулинга[5] (каталог спулера). Другой процесс, демон печати[6], периодически проверяет наличие файлов, которые нужно печатать, печатает файл и удаляет его имя из каталога.

Пусть каталог спулинга состоит из сегментов, пронумерованных 0, 1, 2. в каждом их которых может храниться имя файла. Имеются совместно используемые переменные: out – указывающая на следующий файл для печати; in – указывающая на следующий свободный сегмент. Эти переменные можно хранить в одном файле, доступном всем процессам. Сегменты с 0 по 3 пусты, так как файлы напечатаны, в сегментах с 4 по 6 файлы ждут своей очереди на печать. Конкурирующие процессы А и В решают поставить файл в очередь на печать (рис. 3.6.). Возможна следующая ситуация.

Процесс А считывает значение переменной in и сохраняет его в локальной переменной, например, next_free_slot. После этого происходит прерывание по таймеру, и процессор переключается на процесс В. Процесс В считывает значение переменной in и сохраняет его в своей локальной переменной next_free_slot. В данный момент оба процесса считают, что следующий свободный сегмент – седьмой. Процесс В сохраняет в каталоге спулинга имя файла и заменяет значение in на 8, затем продолжает заниматься другими задачами. Затем управление переходит к процессу А, который продолжает с того места, на котором остановился. Он обращается к переменной next_free_slot, считывает ее значение и записывает в седьмой сегмент свое имя файла, удаляя имя файла, записанное туда процессом В. Затем он заменяет значение in на 8 (next_free_slot +1 = 8). Структура каталога спулинга не нарушена и демон печати не заметит изменений, поэтому файл процесса В не будет напечатан. Ситуации, в которых два и более процесса считывают или записывают данные одновременно и конечный результат зависит от того, какой из них был первым, называются состояниями состязания.

Основным способом предотвращения проблем, связанных с совместным использованием памяти, файлов и др., является запрет одновременной записи и чтения разделенных данных более чем одним процессом. С этой целью используется взаимное исключение – когда один процесс использует разделенные данные, другому процессу это делать запрещено. Выше описанная проблема возникла из-за того, что процесс В начал работу с одной из совместно используемых переменных до того, как процесс А ее закончил.

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

— два процесса не должны одновременно находиться в критических областях;

— в программе не должно быть предположений о скорости или количестве процессоров;

— процесс, находящийся вне критической области, не может блокировать другие процессы;

— должна отсутствовать ситуации, в которой процесс постоянно ждет попадания в критическую область.

Пусть процесс А попадает в критическую область, чуть позже процесс В так же пытается попасть в критическую область, но ему это не удается, поскольку в критической области уже находится процесс А, а два процесса не должны одновременно находиться в критических областях. Поэтому процесс В временно приостанавливает свою работу до наступления момента, когда процесс А выйдет из критической области. Через некоторый момент времени процесс В также покидает критическую область. Происходит возвращение в исходное состояние, когда ни одного процесса в критической области нет. Для реализации взаимного исключения применяется несколько способов.

1.Запрещение прерываний при входе процесса в критическую область и разрешение прерываний при выходе из нее.

2.Использование переменной блокировки. Если процесс хочет попасть в критическую область, он предварительно считывает значение переменной блокировки. Если переменная равна нулю, процесс изменяет ее на 1 и входит в критическую область. Если переменная равна 1, то процесс ждет, пока ее значение не изменится на . Данный метод имеет существенные недостатки. Например, процесс А считывает переменную блокировки и определяет ее значение равное , опередивший его процесс В изменяет значение переменной блокировки на 1. Так как процесс А определил значение переменной как , то он так же заменяет ее на 1 и два процесса могут оказаться в критической области.

3.Строгое чередование. Данный метод требует, чтобы два процесса попадали в критические области строго по очереди. Ни один из них не сможет попасть в критическую область (например, послать файл на печать) два раза подряд. Хотя этот алгоритм и исключает состояния состязания, но он нарушает третье условие успешной работы двух параллельных процессов с совместно используемыми данными.

4.Алгоритм Петерсона. Датский математик Деккер первым разработал программное решение проблемы взаимного исключения, не требующее строгого чередования. В 1981 году Петерсон разработал более простой алгоритм взаимного исключения, который состоит из двух процедур, написанных на ANSI С, что предполагает необходимость прототипов для всех определяемых и используемых функций. Прежде чем обратиться к совместно используемым переменным (войти в критическую область), процесс вызывает процедуру enter_region со своим параметром (0 или 1). Поэтому процессу при необходимости придется подождать, прежде чем входить в критическую область. После выхода из критической области процесс вызывает процедуру leave_region, чтобы обозначить свой выход и тем самым разрешить другому процессу вход в критическую область.

5.Команда TSL. Данное решение требует участия аппаратного обеспечения. Многие процессоры имеют команду TSL RX.LOCK (Test and Set Lock – проверить и заблокировать), которая действует следующим образом. В регистр RX считывается содержимое слова памяти lock, а в ячейке памяти lock сохраняется некоторое ненулевое значение. Гарантируется, что операция считывания слова и сохранения неделима – другой процесс не может обратиться к слову в памяти, пока команда не выполнена. Процессор, выполняющий команду TSL, блокирует шину памяти, чтобы остальные процессоры не могли обратиться к памяти. Прежде чем попасть в критическую область, процесс вызывает процедуру enter_region, которая выполняет активное ожидание вплоть до снятия блокировки, затем она устанавливает блокировку и возвращается. По выходе из критической области процесс вызывает процедуру leave_region, помещающую в переменную lock. Для корректной работы процесс должен вызывать эти процедуры своевременно, в противном случае взаимное исключение не удастся.

Недостатком алгоритма Петерсона и команды TSL является использование активного ожидания, в результате которого бесцельно расходуется время процессора, кроме этого может возникнуть следующая ситуация. Пусть имеется два процесса: А с высоким приоритетом, и В с низким приоритетом. Согласно правилам планирования, процесс А запускается первым из состояния ожидания. Может возникнуть момент, когда процесс В находится в критической области, а процесс А перешел в состояние ожидания (например, закончил операцию ввода-вывода) из которого он переходит в состояние активного ожидания. Так как процессу В во время работающего процесса А никогда не будет предоставлено процессорное время, у процесса В не будет возможности выйти из критической области, и процесс А навсегда останется в цикле. Данную ситуацию называют проблемой инверсии приоритета.

Во избежание такой ситуации вместо циклов ожидания часто используются примитивы межпроцессного взаимодействия, которые блокируют процессы в случае запрета на вход в критическую область. Например, пара примитивов sleep и wakeup. Примитив sleep реализует системный запрос, в результате которого вызывающий процесс блокируется, пока его не запустит другой процесс. Запрос wakeup содержит один параметр – процесс, который следует запустить. Кроме того, у обоих примитивов возможно наличие одного параметра – адреса ячейки памяти, используемой для согласования запросов ожидания и запуска.

В 1965 году Дейкстра (Е.W. Dijkstra) предложил использовать семафоры – целые переменные для подсчета сигналов запуска, сохраненных на будущее. Значение семафоров изменяется от нуля (в случае отсутствия сохраненных сигналов активизации) до некоторого положительного числа, соответствующего количеству отложенных активизирующих сигналов. Дейкстра предложил две операции: down и up (обобщения sleep и wakeup):

— операция down сравнивает значение семафора с нулем; если значение семафора больше нуля – уменьшает его (расходует один из сохраненных сигналов активации) и возвращает управление; если значение семафора равно нулю – процесс переводится в состояние ожидания;

— операция up увеличивает значение семафора; если с семафором связаны ожидающие процессы, которые не могут завершить операцию down, то системой выбирается один и ему разрешается завершение операции down; таким образом, значение семафора останется равным 0, но число ожидающих процессов уменьшится на единицу.

Операции выполняются как единое и неделимое элементарное действие. Этим гарантируется, что после начала операций down ни один процесс не получит доступа к семафору до окончания или блокирования операции и ни один процесс не может быть блокирован во время выполнения операции up.

В ряде случаев используется упрощенная версия семафора – мьютекс (mutex от mutual exclusion – взаимное исключение), который управляет взаимным исключением доступа к совместно используемым ресурсам или кодам. Мьютексы часто используются в случае потоков, действующих только в пространстве пользователя. Мьютекс представляет собой переменную, которая может находиться в одном из двух состояний: блокированном или неблокированном, поэтому для описания мьютекса требуется один бит. Часто используется целая переменная, у которой 0 означает неблокированное состояние, а остальные значения соответствуют блокированному состоянию. Значение мьютекса устанавливается двумя процедурами.

Если поток (или процесс) собирается войти в критическую область, он вызывает процедуру mutex_lock. Если мьютекс не заблокирован (вход в критическую область разрешен), запрос выполняется и вызывающий поток может попасть в критическую область. Если мьютекс заблокирован, вызывающий поток блокируется до тех пор, пока другой поток, находящийся к критической области, не выйдет из нее, вызвав процедуру mutex_unlock. Если мьютекс блокирует несколько потоков, то из них случайным образом выбирается один.

Чтобы упростить написание программ, в 1974 году Хоар (Ноаге) и Бринч Хансен (Brinch Hansen) предложили примитив синхронизации более высокого уровня – монитор, который представляет собой набор процедур, переменных и других структур данных, объединенных в особый модуль или пакет. Процессы могут вызывать процедуры монитора, но у процедур, объявленных вне монитора, нет прямого доступа к внутренним структурам данных монитора. Реализации взаимных исключений способствует важное свойство монитора: при обращении к монитору в любой момент времени активным может быть только один процесс.

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

Мониторы и семафоры были разработаны для решения задачи взаимного исключения в системе с одним или несколькими процессорами, имеющими доступ к общей памяти. Помещение семафоров в разделенную память с защитой в виде команд TSL может исключить состояния состязания. Эти примитивы неприменимы в распределенной системе, состоящей из нескольких процессоров с собственной памятью у каждого, связанных локальной сетью. В этом случае используется механизм передачи сообщений. Этот метод межпроцессного взаимодействия использует два примитива: send и receive, которые являются системными вызовами, а не структурными компонентами языка (что отличает их от мониторов и делает похожим на семафоры). Поэтому их легко можно поместить в библиотечные процедуры, например:

receive(source, message) – получить сообщение от указанного источника.

Если сообщения нет, второй запрос блокируется до поступления сообщения либо немедленно возвращает код ошибки. Примитивы send и receive имеют скрытый механизм взаимоисключения, в большинстве систем они имеют и скрытый механизм блокировки при чтении из пустого буфера и при записи в полностью заполненный буфер. Однако, не смотря на простоту использования, передача сообщений в пределах одного компьютера происходит существенно медленнее, чем работа с семафорами и мониторами.

Передача сообщений часто используется в системах с параллельным программированием, так как данный механизм синхронизации предназначен для групп процессов. Некоторые приложения делятся на фазы, и существует правило, что процесс не может перейти в следующую фазу, пока к этому не готовы остальные процессы. Этого можно добиться, разместив в конце каждой фазы барьер. Когда процесс доходит до барьера, он блокируется, пока все процессы не дойдут до него.

Например, четыре процесса приближаются к барьеру, но они еще заняты вычислениями и не дошли до конца фазы. Через некоторое время первый процесс завершает вычисления, предусмотренные в этой фазе. Он выполняет примитив barrier, вызывая библиотечную процедуру, и приостанавливается. Через некоторое время второй и третий процессы заканчивают первую фазу и выполняют примитив barrier. После того, когда последний процесс достигает барьера, все процессы переходят в следующую фазу.

Дата добавления: 2014-01-07 ; Просмотров: 1502 ; Нарушение авторских прав? ;

Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет

Примитивы и механизм доступа

6. Лекция: Определение и использование примитивов

Определения и классификация примитивов

В спецификации XML термин примитив (entity) в широком смысле относится к любому из следующих типов единиц хранения информации для XML-документов.

Собственно XML-документ как целое.

Внешнее подмножество DTD (см. раздел «Использование внешних подмножеств DTD» в лекции 5).

Внешний файл, определенный как внешний примитив в DTD и допускающий использование посредством ссылки.

Строка в кавычках, определенная как внутренний примитив в DTD и допускающая использование посредством ссылки.

Заметим, что первые три типа единиц хранения информации являются файлами, а последний – строкой символов, заключенных в кавычки.

В этой лекции, термин примитив используется в узком смысле, а именно, для обозначения внешнего файла или строки в кавычках, определенных как примитив в DTD документа и допускающих использование в документе посредством ссылок на примитивы. Например, следующее DTD определяет внешний файл Topics.xml (этот файл содержит список тем в статье, включенной в документ) как внешний примитив с именем topics, а также строку в кавычках («A Short History of XML») как внешний примитив с именем title:

Впоследствии вы можете вставить полный список тем в любое нужное вам место статьи (например, в аннотацию, введение или заключение), просто включив ссылку на примитив &topics; – как для следующего элемента:

Вы можете вставить название статьи в любое место, включив ссылку на примитив &title; – как для следующего элемента:

Механизм примитивов наиболее полезен при наличии часто используемых фрагментов XML-текста. Например, если название статьи многократно фигурирует по ее тексту, использование примитива (как в предыдущем примере) позволит сократить время набора, добиться однородности и облегчить внесение изменений в название. Вы можете изменить текст названия, встречающегося в различных листах статьи, просто отредактировав объявление примитива в DTD. Например:

Если вы знакомы с программированием, то легко уловите сходство между механизмом использования примитивов XML и определением констант в языках программирования (например, объявления с помощью инструкции #define в C).

Механизм примитивов также необходим при включении не XML-данных в XML-документ (например, графические данные для изображения).

Типы примитивов

Существует множество разновидностей примитивов. Материал, излагаемый в этом разделе, может показаться довольно абстрактным (прежде, чем вы познакомитесь с деталями и рассмотрите примеры), возвращение к этой информации впоследствии позволит значительно облегчить восприятие примитивов.

Примитивы классифицируются по трем признакам:

общие и параметрические. Общий примитив включает содержимое документа – т.е. XML-текст или другие текстовые или не текстовые данные, которые вы можете использовать внутри элемента Документ. Оба примера примитивов, рассмотренных в предыдущем разделе (title и topics) относятся к общим примитивам. Параметрический примитив содержит XML-текст, который может быть помещен в DTD. В спецификации XML термин примитив относится к общим примитивам;

внутренние и внешние. Внутренний примитив содержится внутри строки в кавычках (примитив title в предыдущем разделе). Внешний примитив содержится в отдельном файле (примитив topics в предыдущем разделе);


разбираемый или не разбираемый. Разбираемый примитив содержит XML-текст (символьные данные, разметка или то и другое). Когда вы вставляете ссылку на разбираемый примитив в документ, ссылка замещается содержимым примитива (замещающий текст), который становится составной частью документа. Синтаксический анализатор XML разбирает (сканирует) содержимое примитива точно так же, как он сканирует непосредственно введенный в документ текст. Оба примера примитивов, рассмотренных в предыдущем разделе (title и topics) являются разбираемыми примитивами.

Не разбираемый примитив может содержать любой тип данных: XML-данные или, что чаще, не XML-данные. Не XML-данные могут представлять собой либо текстовые данные (например, название) или не текстовые данные (например, графические данные для изображения). Поскольку не разбираемый примитив обычно не содержит XML, его содержимое нельзя непосредственно вставить в документ посредством ссылки на примитив. Тем не менее, вы можете связать с именем примитива атрибут типа ENTITY или ENTITIES, чтобы приложение получило доступ к имени примитива и его описанию, а также могло работать с его данными.

Поскольку примитивы классифицируются по этим трем признакам и в каждой классификации имеются две категории, теоретически существует восемь потенциальных типов примитивов, как показано на диаграмме (см. рис. 6.1).

Однако три типа примитивов из этих восьми в XML не поддерживаются (на диаграмме они зачеркнуты). Следовательно, реально в XML имеется только пять типов примитивов:

общие внутренние разбираемые;

общие внешние разбираемые;

общие внешние не разбираемые;

параметрические внутренние разбираемые;

параметрические внешние разбираемые.

О том, как определять и использовать их, вы и узнаете в этой лекции.

Объявление общих примитивов

Примитив создается путем объявления его в DTD документа. Вы объявляете примитив с использованием разновидности объявления разметки, схожей с той, которая используется для объявления элементов и атрибутов. В последующих разделах вы узнаете, как объявлять каждый из типов общих примитивов.

Объявление общего внутреннего разбираемого примитива

Объявление общего внутреннего разбираемого примитива имеет следующую форму записи:

Здесь ИмяПримитива есть имя примитива. Вы можете выбрать любое имя, следуя следующим правилам:

имя должно начинаться с буквы или с символа подчеркивания (_), после чего может следовать ни одна или несколько букв, цифр, точек (.), тире (–) или символов подчеркивания;

примитив может иметь такое же имя, что и параметрический примитив в документе. (Общие примитивы и параметрические примитивы занимают различные пространства имен.) Примитив также может иметь такое же имя, как элемент или атрибут;

помните, что для всего текста внутри разметки имеет значение регистр, в котором набраны символы. Это относится и к именам примитивов. Так, примитив с именем Bowser и примитив с именем bowser будут считаться различными.

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

строка должна быть заключена в одинарные (‘) или в двойные («) кавычки;

строка не может содержать тот же символ кавычек, который используется в качестве ограничителей;

содержимое строки должно быть корректным для места, в которое вы предполагаете вставить примитив. Например, если вы помещаете примитив внутрь элемента, он должен содержать один или несколько компонентов, которые могут быть корректно вставлены в другие элементы (вложенные элементы, символьные данные и т.д., как описано в разделе «Типы содержимого элемента» в лекции 3). Либо, если вы вставляете примитив внутрь значения атрибута, он должен содержать символы, которые являются допустимыми для значений атрибута (см. раздел «Правила для корректного задания значений атрибутов» в лекции 3). Далее в этой лекции вы узнаете, куда можно помещать общие внутренние разбираемые примитивы.

Например, следующее DTD определяет общий внутренний разбираемый примитив с именем title:

Примитив title содержит символьные данные плюс элемент (SUBTITLE). В соответствии с объявлением в DTD это содержимое может быть корректно вставлено только в элемент TITLEPAGE, как показано ниже:

XML-процессор заменит ссылку на примитив (&title;) содержимым примитива и обработает содержимое, как если бы вы непосредственно набрали его в документе в позиции ссылки, подобно следующему:

Объявление общего внешнего разбираемого примитива

Объявление для общего внешнего разбираемого примитива имеет следующую форму записи:

Здесь ИмяПримитива есть имя примитива. Вы можете выбрать любое имя, следуя правилам задания имен для общих примитивов, приведенным в предыдущем разделе.

СистемЛитерал есть системный литерал, который описывает местонахождение файла, содержащего данные примитива. Системный литерал может быть ограничен одинарными (‘) или двойными («) кавычками и содержать любые символы, кроме символа кавычек, используемого как ограничители.

Системный литерал задает унифицированный идентификатор ресурса (URI) файла, содержащего данные примитива. На сегодняшний день URI практически то же самое, что стандартный Internet-адрес, известный как унифицированный указатель ресурса (URL). Вы можете использовать либо полный URI, например:

либо частичный URI, который задает местонахождение относительно местонахождения XML-документа, содержащего URI, например:

Относительные URI в XML-документах работают аналогично относительным URL для HTML-страниц. Для более подробной информации об URI обратитесь к разделу «Использование только внешнего подмножества DTD» в лекции 5.

Илон Маск рекомендует:  Что такое код zip_open

Файл внешнего примитива может содержать только те составляющие, которые могут быть корректно вставлены в элемент (символьные данные, вложенные элементы и т.д., как описано в разделе «Типы содержимого элемента» в лекции 3). Вы можете вставить общий внешний разбираемый примитив только внутрь содержимого элемента. (Можно включить его в значение в объявлении внутреннего примитива, но затем нужно вставить это содержимое в элемент.)

Например, следующее DTD определяет внешний файл Topics.xml как общий внешний разбираемый примитив:

Вот содержимое файла Topics.xml:

Этот типичный файл внешнего примитива содержит два пункта, которые вы можете включить в XML-элемент: вложенный элемент и блок символьных данных. Его содержимое может быть корректно вставлено в элемент INTRODUCTION (который иметь любой тип содержимого), как показано в следующем примере:

Объявление общего внешнего не разбираемого примитива

Объявление для общего внешнего не разбираемого примитива имеет следующую форму записи:

Здесь ИмяПримитива есть имя примитива. Вы можете выбрать любое имя, следуя правилам, приведенным в разделе «Объявление общего внутреннего разбираемого примитива» ранее в этой лекции.

СистемЛитерал есть системный литерал, который описывает местонахождение файла, содержащего данные примитива. Он действует точно так же, как системный литерал для описания местоположения общего внешнего разбираемого примитива (см. предыдущий раздел).

Примечание. Ключевое слово NDATA указывает, что файл примитива содержит не разбираемые данные (они не обрабатываются синтаксическим анализатором).

ИмяНотации есть имя нотации, объявленной в DTD. Нотация описывает формат данных, содержащихся в файле примитива, или указывает на местонахождение программы, которая может обрабатывать эти данные. Об объявлении нотации будет говориться в следующем разделе.

Файл не разбираемого внешнего примитива может содержать любой тип текста или не текстовые данные. Они должны, конечно, соответствовать описанию формата, определяемого соответствующей нотацией.

Например, DTD в следующем XML-документе определяет файл Faun.gif (который содержит рисунок обложки книги) как общий внешний не разбираемый примитив с именем faun. Имя нотации этого примитива – GIF. Она указывает на местонахождение программы, которая отображает графические файлы в формате GIF (ShowGif.exe). DTD также определяет пустой элемент с именем COVERIMAGE и атрибут типа ENTITY для этого элемента с именем Source:

В элементе Документ атрибуту Source элемента COVERIMAGE присвоено имя внешнего примитива, который содержит графические данные для отображения рисунка обложки. Поскольку Source имеет тип ENTITY, вы можете присвоить ему имя общего внешнего не разбираемого примитива. Фактически единственный способ использования этого типа примитива состоит в присвоении его имени атрибуту с типом ENTITY или ENTITIES.

Примечание. В отличие от файла внешнего разбираемого примитива, к файлу внешнего не разбираемого примитива XML-процессор прямого доступа не имеет. Процессор просто делает примитив и его нотацию доступными приложению, которое может выполнять необходимые действия с этой информацией. (Например, оно может запустить программу, ассоциированную с нотацией, и указать ей отобразить данные из файла примитива.) В лекции 9 вы узнаете, как писать сценарии Web-страниц, которые могут получать доступ к примитивам и нотациям.

Объявление нотаций

Нотация описывает определенный формат данных. Это делается путем указания адреса описания формата, адреса программы, которая может обрабатывать данные в этом формате, либо просто описание формата. Вы можете использовать нотацию, чтобы описать формат общего внешнего не разбираемого примитива (см. в предыдущем разделе), либо можете присвоить нотацию атрибуту, который имеет нумерованный тип NOTATION (см. раздел «Задание нумерованных типов» в лекции 5).

Нотация имеет следующую форму записи:

Здесь ИмяНотации есть имя нотации. Вы можете выбрать любое имя, при условии, что оно начинается с буквы или символа подчеркивания (_), после чего могут идти или не идти другие буквы, цифры, точки (.), тире (–) или символы подчеркивания. Лучше выбирать информативное имя, позволяющее идентифицировать формат. Например, если вы определяете нотацию, описывающую точечный формат (bitmap), вам следует использовать имя BMP.

СистемЛитерал есть системный литерал, который может быть ограничен одинарными (‘) или двойными («) кавычками и содержать любые символы, за исключением символа кавычек, используемого в качестве ограничителя. Вы можете включить в системный литерал любое описание формата, которое проинформирует приложение, как отображать или обрабатывать XML-документ. (Помните, что XML-процессор сам не использует информацию нотации; он просто передает ее приложению, в качестве которого может выступать сценарий на Web-странице.) Например, вы можете включить в системный литерал одно из следующих описаний.

URI программы, которая может обрабатывать или отображать формат данных, как в следующих примерах:

URI документа в сети, который описывает формат данных, например:

Простое описание формата, например:

Дополнительная информация об URI и примеры приведены в разделе «Использование только внешнего подмножества DTD» в лекции 5.

Объявление параметрических примитивов

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

Объявление параметрического внутреннего разбираемого примитива

Объявление для параметрического внутреннего разбираемого примитива имеет следующую общую форму записи:

Здесь ИмяПримитива есть имя примитива. Вы можете выбрать любое имя, соблюдая следующие правила:

имя должно начинаться с буквы или символа подчеркивания (_), вслед за которым могут идти или не идти буквы, цифры, точки (,), тире (–) или символы подчеркивания;

примитив может иметь такое же имя, что и общий примитив в документе. (Параметрические и общие примитивы занимают различные пространства имен.) Имя примитива также может совпадать с именем элемента или атрибута;

помните, что для всего текста разметки, в том числе и для имен примитивов, имеет значение регистр, в котором набраны символы. Так, примитив под именем Spot будет отличаться от примитива под именем spot.

ЗначениеПримитива есть значение примитива. Значение, присваиваемое параметрическому примитиву, представляет собой группу символов, заключенных в кавычки (литерал). Вы можете присвоить параметрическому примитиву любое значение типа литерал, при условии соблюдения следующих правил:

строка должна быть ограничена одинарными (‘) или двойными («) кавычками;

строка не может содержать символов кавычек, которые используются в качестве ограничителей;

строка не может содержать символа процентов (%) и символа амперсанда (&), если это не начальный символ в ссылке на символ или общий примитив;

вы можете поместить параметрический примитив в DTD только как объявление разметки, но не внутри объявления разметки. Следовательно, строка ЗначениеПримитива должна содержать один или несколько типов объявлений разметки, которые разрешено использовать в DTD. Эти типы объявлений разметки описаны в разделе «Создание DTD» в лекции 5. В частности, параметрический примитив может содержать объявления типа элемента, объявления списка атрибутов, объявления общих примитивов, объявления нотаций, инструкции по обработке, или комментарии. (Объявления параметрических примитивов и ссылки не допускаются.)

Примечание. Приведенные здесь правила использования значений примитивов, которые вы можете без опасения применять в любых ситуациях, являются несколько упрощенными в отличие от правил, содержащихся в спецификации XML. Спецификация, в определенных обстоятельствах, разрешает вам включать в значение примитива дополнительные составляющие, а также помещать ссылку на примитив внутри разметки и между объявлениями разметки. Подробности приведены в разделе 4 спецификации XML, которую вы можете найти по адресу http://www.w3.org/TR/REC-xml.


Например, следующее DTD объявляет параметрический внутренний не разбираемый примитив с именем author, который содержит три объявления разметки: комментарий, объявление типа элемента и объявление списка атрибутов. Содержимое примитива (т.е. замещающий его текст) помещается в конец DTD посредством ссылки на параметрический примитив (%author;);

Обратите внимание, что значение атрибута по умолчанию, которое содержится в объявлении примитива (‘American’), ограничено одинарными кавычками, чтобы избежать использования такого же символа, который применяется для ограничения всего значения примитива. Приведенное выше DTD эквивалентено следующему:

Объявление параметрического внешнего разбираемого примитива

Объявление для параметрического внешнего разбираемого примитива имеет следующую форму записи:

Здесь ИмяПримитива есть имя примитива. Вы можете выбрать любое имя, следуя правилам задания имен для параметрических примитивов, приведенных в предыдущем разделе.

СистемЛитерал есть системный литерал, который описывает местонахождение файла, содержащего данные примитива. Системный литерал может быть заключен в одинарные (‘) или двойные («) кавычки и содержать любые символы, за исключением символа кавычек, который используется в качестве ограничителя.

Системный литерал задает URI файла, содержащего данные параметрического примитива. В настоящее время URI практически аналогичен стандартному унифицированному указателю ресурса Internet (URL). Вы можете использовать как полностью заданный URI, например:

Либо вы можете использовать частичный URI, задающий местонахождение относительно местонахождения XML-документа, содержащего URI, например:

Относительные URI в XML-документах работают подобно относительным URL для HTML-страниц. Для более подробной информации об URI обратитесь к разделу «Использование только внешнего подмножества DTD» в лекции 5.

Файл параметрического внешнего примитива должен содержать полные объявления разметки всех типов, допустимых в DTD. В частности, он может содержать объявления типа элемента, объявления списка атрибутов, объявления примитивов, объявления нотаций, инструкции по обработке, или комментарии. (Эти типы объявлений разметки описаны в разделе «Создание DTD» в лекции 5.) Вы также можете включать ссылки на параметрические примитивы и разделы INCLUDE и IGNORE. (См. раздел «Условное игнорирование разделов внешнего подмножества DTD» в лекции 5.)

Вы можете использовать параметрические внешние разбираемые примитивы для хранения группы взаимосвязанных объявлений. Допустим, вы занимаетесь продажей книг, CD-ROM, плакатов и другой продукции. Вы можете поместить объявления для каждого вида продукции в отдельный файл. Это позволит вам объединять эти группы объявлений различными способами. Например, вы хотели бы создать XML-документ, который описывает только имеющиеся у вас в наличии книги и CD-ROM. Для этого вы можете поместить объявления для книг и CD-ROM в DTD документа с помощью параметрических внешних разбираемых примитивов, как показано в следующем примере XML-документа:

Вот содержимое файла примитива Book.dtd:

А вот содержимое файла примитива CD.dtd:

Заметим, что параметрический внешний разбираемый примитив работает во многом аналогично внешнему подмножеству DTD. Параметрические внешние примитивы, однако, обеспечивают большую гибкость – они разрешают вам включать несколько файлов внешних объявлений, причем в любом порядке. (Напомним, что внешнее подмножество DTD всегда обрабатывается после того, как полностью будет обработано подмножество внутреннего DTD.)

Вставка ссылок на примитив

Вставка содержимого (замещающий текст) примитива в документ осуществляется с помощью ссылок на примитив. Вы уже познакомились с несколькими примерами ссылок на примитив. Общий вид ссылки на общий примитив следующий:

а на параметрический примитив:

где ИмяПримитива есть имя, присваиваемое примитиву в объявлении. Исключением является общий внешний не разбираемый примитив, который вы не можете вставить с использованием ссылки. Единственный способ использования этого типа примитива заключается в присвоении его имени атрибуту, имеющему тип ENTITY или ENTITIES. (См. раздел «Задание маркерного типа» в лекции 5.)

Объявление примитива должно предшествовать любой ссылке на этот примитив.

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

Форма записи ссылки на примитив, где ИмяПримитива есть имя примитива

Место, в которое вы можете поместить ссылку на примитив (пример)

Общий внутренний разбираемый

В содержимое элемента (см. «Объявление общего внутреннего разбираемого примитива»)

В значение атрибута (как значение по умолчанию в объявлении атрибута, либо в начальном теге элемента) (см. «Ссылка на примитив Пример 1»)

В значение в объявлении внутреннего примитива (см. «Ссылка на примитив Пример 2»)

Общий внешний разбираемый

В содержимое элемента (см. «Объявление общего внешнего разбираемого примитива»)

Общий внешний не разбираемый

где АтрПрим есть атрибут типа ENTITY или ENTITIES

В значение в объявлении внутреннего примитива (см. «Ссылка на примитив Пример 2»)

Вы не можете поместить ссылку на этот тип примитива, но можете присвоить имя примитива атрибуту, имеющему тип ENTITY или ENTITIES (см. «Объявление общего внешнего не разбираемого примитива»)

Параметрический внутренний разбираемый

В DTD в место помещения объявлений разметки, но не внутри объявлений разметки (исключения приведены в разделе 4 спецификации XML, доступ по адресу http://www.w3.org/TR/REC-xml) (см. «Объявление параметрического внутреннего разбираемого примитива»)

Параметрический внешний разбираемый

В DTD в место помещения объявлений разметки, но не внутри объявлений разметки (исключения приведены в разделе 4 спецификации XML, доступ по адресу http://www.w3.org/TR/REC-xml) (см. «Объявление параметрического внешнего разбираемого примитива»)

Ссылка на символ

или &#xh; где 9 – десятичный числовой код символа, а h – шестнадцатеричный числовой код символа

В содержимое элемента (см. «Вставка ссылок на символы»)

В значение атрибута (в качестве значения по умолчанию в объявление списка атрибутов, или в начальный тег элемента) (см. «Вставка ссылок на символы»)

В значение в объявлении внутреннего примитива (см. «Вставка ссылок на символы»)

Ссылка на примитив Пример 1

В следующем XML-документе объявлены два общих внутренних разбираемых примитива, am и en. Документ использует ссылку на am для присвоения значения по умолчанию атрибуту Nationality и ссылку на en для присвоения значения атрибуту Nationality элемента AUTHOR. Преимущество использования примитива здесь заключается в том, что вы можете изменить значение по всему документу (в предположении, что в нем имеется много элементов) простым редактированием определения примитива (например, изменив значение en с «English» на «British»).

Ссылка на примитив Пример 2

Следующее DTD определяет общий внутренний разбираемый примитив (int_entity) и общий внешний разбираемый примитив (ext_entity). Затем он определяет другой общий внутренний разбираемый примитив, combo_entity, и помещает оба предыдущих примитива в значение примитива combo_entity.

Вставка ссылок на символы

Вы можете воспользоваться ссылкой на символ, чтобы вставить символ, которого нет на вашей клавиатуре (например, a), либо вставить символ, который не допускает его вставку в данном контексте как литерал (например, символы

Например, из рисунка вы можете определить, что десятичный код символа для a равен 228. Чтобы вставить этот символ в ваш документ, достаточно ввести ссылку:

Примечание. Список мест, в которые вы можете поместить ссылку на символ в вашем документе, приведен в таблице в разделе «Вставка ссылок на примитивы» ранее в этой лекции. Там же приведены и примеры.

Для следующего элемента символ левой угловой скобки (

ГЛАВА 6 Определение и использование примитивов

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

Вы определяете примитив в описании типа документа (DTD) с использованием синтаксиса, аналогичного тому, который используется для объявления элемента или атрибута в валидном XML-документе. О DTD и объявлениях типа документа, содержащего их, говорилось в главе 5.

В этой главе вы прежде всего познакомитесь с основной терминологией, используемой для примитивов, а также с различными способами классификации примитивов. Затем вы узнаете, как объявлять каждый из примитивов различных типов и как вставлять примитивы в ваш документ в необходимом месте. Далее вы узнаете, как использовать возможности XML, которые позволяют вам вставлять любые типы символов в любом контексте: как ссылки на символ и как ссылки на примитивы. В конце главы имеется упражнение, которое позволит вам попрактиковаться в использовании примитивов в полном XML-документе.

Определения и классификация примитивов

В спецификации XML термин примитив (entity) в широком смысле относится к любому из следующих типов единиц хранения информации для XML-документов.

  • Собственно XML-документ как целое.
  • Внешнее подмножество DTD (см. раздел « Использование внешних подмножеств DTD» в главе 5).
  • Внешний файл, определенный как внешний примитив в DTD и допускающий использование посредством ссылки.
  • Строка в кавычках, определенная как внутренний примитив в DTD и допускающая использование посредством ссылки.

Заметим, что первые три типа единиц хранения информации являются файлами, а последний — строкой символов, заключенных в кавычки.

В этой главе термин примитив используется в узком смысле, а именно, для обозначения внешнего файла или строки в кавычках, определенных как примитив в DTD документа и допускающих использование в документе посредством ссылок на примитивы. Например, следующее DTD определяет внешний файл Topics.xml (этот файл содержит список тем в статье, включенной в документ) как внешний примитив с именем topics, a также строку в кавычках («A Short History of XML») как внешний примитив с именем title:

Впоследствии вы можете вставить полный список тем в любое нужное вам место статьи (например, в аннотацию, введение или заключение), просто включив ссылку на примитив &topics;

This article will cover the following topics:

Вы можете вставить название статьи в любое место, включив ссылку на примитив & title;

Author: Michael Young

Механизм примитивов наиболее полезен при наличии часто используемых фрагментов XML-текста. Например, если название статьи многократно фигурирует по ее тексту, использование примитива (как в предыдущем примере) позволит сократить время набора, добиться однородности и облегчить внесение изменений в название. Вы можете изменить текст названия, встречающегося в различных листах статьи, просто отредактировав объявление примитива в DTD. Например:

Если вы знакомы с программированием, то легко уловите сходство между механизмом использования примитивов XML и определением констант в языках программирования (например, объявления с помощью инструкции #define в С).

Механизм примитивов также необходим при включении не XML-данных в XML-документ (например, графические данные для изображения).

Существует множество разновидностей примитивов. Материал, излагаемый в этом разделе, может показаться довольно абстрактным (прежде, чем вы познакомитесь с деталями и рассмотрите примеры), возвращение к этой информации впоследствии позволит значительно облегчить вос-] фиятие примитивов.

Примитивы классифицируются по трем признакам:


  • общие и параметрические. Общий примитив включает содержимое документа — т.е. XML-текст или другие текстовые или не текстовые данные, которые пы можете использовать внутри элемента Документ. Оба примера примитивов, рассмотренных в предыдущем разделе (title и topics) относятся к общим примитивам. Параметрический примитив содержит XML-текст, который может быть помещен в DTD. В спецификации XML термин примитив относится к общим примитивам;
  • внутренние и внешние. Внутренний примитив содержится внутри строки в кавычках (примитив title в предыдущем разделе). Внешний примитив содержится в отдельном файле (примитив topics в предыдущем разделе);
  • разбираемый или не разбираемый. Разбираемый примитив содержит XML-текст (символьные данные, разметка или то и другое). Когда вы вставляете ссылку на разбираемый примитив в документ, ссылка замещается содержимым примитива (замещающий текст), который становится составной частью документа. Синтаксический анализатор XML разбирает (сканирует) содержимое примитива точно так же, как он сканирует непосредственно введенный в документ текст. Оба примера примитивов, рассмотренных в предыдущем разделе (title и topics) являются разбираемыми примитивами.

Не разбираемый примитив может содержать как XML-данные, так и не XML-данные. Не XML-данные могут представлять собой либо текстовые данные (например, название) или не текстовые данные (например, графические данные для изображения). Поскольку не разбираемый примитив обычно не содержит XML, его содержимое нельзя непосредственно вставить в документ посредством ссылки на примитив. Тем не менее, вы можете связать с именем примитива атрибут типа ENTITY или ENTITIES, чтобы приложение получило доступ к имени примитива и его описанию, а также могло работать с его данными.

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

Однако три типа примитивов из этих восьми в XML не поддерживаются (на диаграмме они зачеркнуты). Следовательно, реально в XML имеется только пять типов примитивов:

  • общие внутренние разбираемые;
  • общие внешние разбираемые;
  • общие внешние не разбираемые;
  • параметрические внутренние разбираемые;
  • параметрические внешние разбираемые.

О том, как определять и использовать их, вы и узнаете в этой главе.

Объявление общих примитивов

Примитив создается путем объявления его в DTD документа. Вы объявляете примитив с использованием разновидности объявления разметки, схожей с той, которая используется для объявления элементов и атрибутов. В последующих разделах вы узнаете, как объявлять каждый из типов общих примитивов.

Объявление общего внутреннего разбираемого примитива

Объявление общего внутреннего разбираемого примитива имеет следующую форму записи:

Здесь ИмяПримитива есть имя примитива. Вы можете выбрать любое имя, следуя следующим правилам:

  • имя должно начинаться с буквы или с символа подчеркивания (_), после чего может следовать ни одна или несколько букв, цифр, точек (.), тире (-) или символов подчеркивания;
  • примитив может иметь такое же имя, что и параметрический примитив в документе. (Общие примитивы и параметрические примитивы занимают различные пространства имен.) Примитив также может иметь такое же имя, как элемент или атрибут;
  • помните, что для всего текста внутри разметки имеет значение регистр, в котором набраны символы. Это относится и к именам примитивов. Так, примитив с именем Bowser и примитив с именем bowser будут считаться различными.

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

  • строка должна быть заключена в одинарные (‘) или в двойные («) кавычки;
  • строка не может содержать тот же символ кавычек, который используется в качестве ограничителей;
  • строка не может содержать символ амперсенда (&), если только он не используется в качестве первого символа в указании ссылки на символ или на общий примитив. Строка также не должна содержать символ процентов (%). (Чтобы познакомиться с возможными исключениями, обратитесь к разделу 4 спецификации XML, которую вы можете найти по адресу http://www.w3.org/TR/REC-xml.);
  • содержимое строки должно быть корректным для места, в которое вы предполагаете вставить примитив. Например, если вы помещаете примитив внутрь элемента, он должен содержать один или несколько компонентов, которые могут быть корректно вставлены в другие элементы (вложенные элементы, символьные данные и т.д., как описано в разделе «Типы содержимого элемента» в главе 3). Если вы вставляете примитив внутрь значения атрибута, он должен содержать символы, которые являются допустимыми для значений атрибута (см. раздел «Правила для корректного задания значений атрибутов» в главе 3). Далее в этой главе вы узнаете, куда можно помещать общие внутренние разбираемые примитивы.

Например, следующее DTD определяет общий внутренний разбираемый примитив с именем title:

‘The Story of XML»

The Future Language of the lnternet «>

Примитив title содержит символьные данные плюс элемент (SUBTITLE). В соответствии с объявлением в DTD это содержимое может быть корректно вставлено только в элемент TITLEPAGE, как показано ниже:

Author: Michael Young

XML-процессор заменит ссылку на примитив &title; содержимым примитива и обработает содержимое, как если бы вы непосредственно набрали его в документе в позиции ссылки, подобно следующему:

Title: The Story of XML

The Future Language of the lnternet

Author: Michael Young

Объявление общего внешнего разбираемого примитива

Объявление для общего внешнего разбираемого примитива имеет следующую форму записи:

Здесь Имя Примитива есть имя примитива. Вы можете выбрать любое имя, следуя правилам задания имен для общих примитивов, приведенным в предыдущем разделе.

Систем Литерал есть системный литерал, который описывает местонахождение файла, содержащего данные примитива. Системный литерал может Пить ограничен одинарными (‘) или двойными («) кавычками и содержать любые симшиил, кроме символа кавычек, используемого как ограничители.

Системный литерал задает унифицированный идентификатор ресурса (URI) файла, содержащего данные примитива. На сегодняшний день URI -практически то же самое, что стандартный Internet-адрес, известный как унифицированный указатель ресурса (URL). Вы можете использовать либо полный URI, например:

либо частичный URI, который задает местонахождение относительно местонахождения XML-документа, содержащего URI, например:

Относительные URI в XML-документах работают аналогично относительным URL для HTML-страниц. Для более подробной информации об URI обратитесь к разделу «Использование только внешнего подмножества DTD» в главе 5.

Файл внешнего примитива может содержать только те составляющие, которые могут быть корректно вставлены в элемент (символьные данные, вложенные элементы и т.д., как описано в разделе «Типы содержимого элемента» в главе 3). Вы можете вставить общий внешний разбираемый примитив только внутрь содержимого элемента. (Можно включить его в значение в объявлении внутреннего примитива, но затем нужно вставить это содержимое в элемент.)

Например, следующее DTD определяет внешний файл Topics.xml как общий внешний разбираемый примитив:

Вот содержимое файла Topics.xml:

The Need for XML

The Official Goals of XML

Standard XML Applications

Real-World Uses for XML

Этот типичный файл внешнего примитива содержит два пункта, которые вы можете включить в XML-элемент: вложенный элемент и блок символьных данных. Его содержимое может быть корректно вставлено в элемент INTRODUCTION (который иметь любой тип содержимого), как показано в следующем примере:

Here’s what this article covers:

Объявление общего внешнего не разбираемого примитива

Объявление для общего внешнего не разбираемого примитива имеет следующую форму записи:

Здесь ИмяПримитива есть имя примитива. Вы можете выбрать любое имя, следуя правилам, приведенным в разделе «Объявление общего внутреннего разбираемого примитива» ранее в этой главе.

СистемЛитерал есть системный литерал, который описывает местонахождение файла, содержащего данные примитива. Он действует точно так же, как системный литерал для описания местоположения общего внешнего разбираемого примитива (см. предыдущий раздел).

Примечание. Ключевое слово NDATA указывает, что файл примитива содержит не разбираемые данные (они не обрабатываются синтаксическим анализатором).

Имя Нотации есть имя нотации, объявленной в DTD. Нотация описывает формат данных, содержащихся в файле примитива, или указывает на местонахождение программы, которая может обрабатывать эти данные.

Файл не разбираемого внешнего примитива может содержать любой тип текста или не текстовые данные. Они должны, конечно, соответствовать описанию формата, определяемого соответствующей нотацией.

Например, DTD в следующем XML-документе определяет файл Faun.gif (который содержит рисунок обложки книги) как общий внешний не разбираемый примитив с именем faun. Имя нотации этого примитива — GIF. ()на указывает на местонахождение программы, которая отображает графические файлы в формате GIF (ShowGif.exe). DTD также определяет пустой элемент с именем СОVERIMAGE и атрибут типа ENTI.TY для этого элемента с именем Source:

Илон Маск рекомендует:  Предопределённые константы ncurses

The Marble Faun

В элементе Документ атрибуту Source элемента COVERIMAGE присвоено имя внешнего примитива, который содержит графические данные для отображения рисунка обложки. Поскольку Source имеет тип ENTITY, вы можете присвоить ему имя общего внешнего не разбираемого примитива. Фактически единственный способ использования этого типа примитива состоит в присвоении его имени атрибуту с типом ENTITY или ENTITIES.

Примечание. В отличие от файла внешнего разбираемого примитива, к файлу внешнего не разбираемого примитива XML-процессор прямого доступа не имеет. Процессор просто делает примитив и его нотацию доступными приложению, которое может выполнять необходимые действия с этой информацией. (Например, оно может запустить программу, ассоциированную с нотацией, и указать ей отобразить данные из файла примитива.) В главе 9 вы узнаете, как писать сценарии Web-страниц, которые могут получать доступ к примитивам и нотациям.

Нотация описывает определенный формат данных. Это делается путем указания адреса описания формата, адреса программы, которая может обрабатывать данные в этом формате, либо просто описание формата. Вы можете использовать нотацию, чтобы описать формат общего внешнего не разбираемого примитива (см. в предыдущем разделе), либо можете присвоить нотацию атрибуту, который имеет нумерованный тип NOTATION (см. раздел «Задание нумерованных типов» в главе 5).

Нотация имеет следующую форму записи:

Здесь Имя Нотации есть имя нотации. Вы можете выбрать любое имя, при условии, что оно начинается с буквы или символа подчеркивания (_), после чего могут идти или не идти другие буквы, цифры, точки (.), тире (-) или символы подчеркивания. Лучше выбирать информативное имя, позволяющее идентифицировать формат. Например, если вы определяете нотацию, описывающую точечный формат (bitmap), вам следует использовать имя BMP.

Систем Литерал есть системный литерал, который может быть ограничен одинарными (‘) или двойными («) кавычками и содержать любые символы, за исключением символа кавычек, используемого в качестве ограничителя. Вы можете включить в системный литерал любое описание формата, которое проинформирует приложение, как отображать или обрабатывать XML-документ. (Помните, что XML-процессор сам не использует информацию нотации; он просто передает ее приложению, в качестве которого может выступать сценарий на Web-странице.) Например, вы можете включить в системный литерал одно из следующих описаний.

  • URI программы, которая может обрабатывать или отображать формат данных, как в следующих примерах:
  • URI документа в сети, который описывает формат данных, например:
  • Простое описание формата, например:

Дополнительная информация об URI и примеры приведены в разделе «Использование только внешнего подмножества DTD» в главе 5.

Объявление параметрических примитивов

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

Объявление параметрического внутреннего разбираемого примитива


Объявление для параметрического внутреннего разбираемого примитива имеет следующую общую форму записи:

Здесь ИмяПримитива есть имя примитива. Вы можете выбрать любое имя, соблюдая следующие правила:

  • имя должно начинаться с буквы или символа подчеркивания (_), вслед за которым могут идти (или не идти) буквы, цифры, точки, тире или символы подчеркивания;
  • примитив может иметь такое же имя, что и общий примитив в документе. (Параметрические и общие примитивы занимают различные пространства имен.) Имя примитива также может совпадать с именем элемента или атрибута;
  • помните, что для всего текста разметки, в том числе и для имен примитивов, имеет значение регистр, в котором набраны символы. Так, . примитив под именем Spot будет отличаться от примитива под именем spot.

ЗначениеПримитива есть значение примитива. Значение, присваиваемое параметрическому примитиву, представляет собой группу символов, заключенных в кавычки (литерал). Вы можете присвоить параметрическому примитиву любое значение типа литерал, при соблюдении следующих правил:

  • строка должна быть ограничена одинарными (‘) или двойными («) кавычками;
  • строка не может содержать символов кавычек, которые используются в качестве ограничителей;
  • строка не может содержать символа процентов (%) и символа амперсенда (&), если это не начальный символ в ссылке на символ или общий примитив;
  • вы можете поместить параметрический примитив в DTD только как объявление разметки, но не внутри объявления разметки. Следовательно, строка ЗначениеПримитива должна содержать один или несколько типов объявлений разметки, которые разрешено использовать в DTD. Эти типы объявлений разметки описаны в разделе «Создание DTD» в главе 5. В частности, параметрический примитив может содержать объявления типа элемента, объявления списка атрибутов, объявления общих примитивов, объявления нотаций, инструкции по обработке, или комментарии. (Объявления параметрических примитивов и ссылки не допускаются.)

Примечание. Приведенные здесь правила использования значений примитивов, которые вы можете без опасения применять в любых ситуациях, являются несколько упрощенными в отличие от правил, содержащихся в спецификации XML. Спецификация, в определенных обстоятельствах, разрешает вам включать в значение примитива дополнительные составляющие, а также помещать ссылку на примитив внутри разметки и между объявлениями разметки. Подробности приведены в разделе 4 спецификации XML, которую вы можете найти по адресу http://www.w3.org/TR/REC-xml.

Например, следующее DTD объявляет параметрический внутренний не разбираемый примитив с именем author, который содержит три объявления разметки: комментарий, объявление типа элемента и объявление списка атрибутов. Содержимое примитива (т.е. замещающий его текст) помещается в конец DTD посредством ссылки на параметрический примитив (%author;);

Обратите внимание, что значение атрибута по умолчанию, которое содержится в объявлении примитива (‘American’), ограничено одинарными кавычками, чтобы избежать использования такого же символа, который применяется для ограничения всего значения примитива. Приведенное выше DTD эквивалентно следующему:

Объявление параметрического внешнего разбираемого примитива

Объявление для параметрического внешнего разбираемого примитива имеет следующую форму записи:

Здесь Имя Примитива есть имя примитива. Вы можете выбрать любое имя, следуя правилам задания имен для параметрических примитивов, приведенных в предыдущем разделе.

Систем Литерал есть системный литерал, который описывает местонахождение файла, содержащего данные примитива. Системный литерал может быть заключен в одинарные (‘) или двойные («) кавычки и содержать любые символы, за исключением символа кавычек, который используется в качестве ограничителя.

Системный литерал задает URI файла, содержащего данные параметрического примитива. В настоящее время URI практически аналогичен стандартному унифицированному указателю ресурса Internet (URL). Вы можете использовать как полностью заданный URI, например:

Либо вы можете использовать частичный URI, задающий местонахождение относительно местонахождения XML-документа, содержащего URI, например:

Относительные URI в XML-документах работают подобно относительным URL для HTML-страниц. Для более подробной информации об URI обратитесь к разделу «Использование только внешнего подмножества DTD» в главе 5.

Файл параметрического внешнего примитива должен содержать полные объявления разметки всех типов, допустимых в DTD. В частности, он может содержать объявления типа элемента, объявления списка атрибутов, объявления примитивов, объявления нотаций, инструкции по обработке, или комментарии. (Эти типы объявлений разметки описаны в разделе «Создание DTD» в главе 5.) Вы также можете включать ссылки на параметрические примитивы и разделы INCLUDE и IGNORE. (См. раздел «Условное игнорирование разделов внешнего подмножества DTD» в главе 5.)

Вы можете использовать параметрические внешние разбираемые примитивы для хранения группы взаимосвязанных объявлений. Допустим, вы занимаетесь продажей книг, CD-ROM, плакатов и другой продукции. Вы можете поместить объявления для каждого вида продукции в отдельный файл. Это позволит вам объединять эти группы объявлений различными способами. Например, вы хотели бы создать XML-документ, который описывает только имеющиеся у вас в наличии книги и CD-ROM. Для этого вы можете поместить объявления для книг и CD-ROM в DTD документа с помощью параметрических внешних разбираемых примитивов, как показано в следующем примере XML-документа:

Определение и использование примитивов

Определения и классификация примитивов

Механизм примитивов в XML является средством повышения производительности, а также способом встраивать различные типы данных в ваш XML -документ. В XML -документе вы можете определить часто используемый блок XML -текста как примитив, что позволяет вам быстро вставлять текст в нужное место . Вы можете также определить как примитив внешний файл , чтобы иметь возможность включать данные файла в вашем документе; эти данные могут содержать XML -текст, другой текст, либо не текстовые данные. Вы определяете примитив в описании типа документа ( DTD ) с использованием синтаксиса, аналогичного тому, который используется для объявления элемента или атрибута в валидном XML -документе. О DTD и объявлениях типа документа , содержащего их, говорилось в «Создание валидных XML-документов» .

В спецификации XML термин примитив ( entity ) в широком смысле относится к любому из следующих типов единиц хранения информации для XML -документов.

  • Собственно XML-документ как целое.
  • Внешнее подмножество DTD (см. раздел «Использование внешних подмножеств DTD» в «Создание валидных XML-документов» ).
  • Внешний файл, определенный как внешний примитив в DTD и допускающий использование посредством ссылки.
  • Строка в кавычках, определенная как внутренний примитив в DTD и допускающая использование посредством ссылки.

Заметим, что первые три типа единиц хранения информации являются файлами, а последний – строкой символов, заключенных в кавычки.

В этой лекции термин примитив используется в узком смысле, а именно, для обозначения внешнего файла или строки в кавычках, определенных как примитив в DTD документа и допускающих использование в документе посредством ссылок на примитивы. Например, следующее DTD определяет внешний файл Topics . xml (этот файл содержит список тем в статье, включенной в документ) как внешний примитив с именем topics , а также строку в кавычках («A Short History of XML «) как внутрений примитив с именем title :

Впоследствии вы можете вставить полный список тем в любое нужное вам место статьи (например, в аннотацию, введение или заключение), просто включив ссылку на примитив & topics ; – как для следующего элемента:

Вы можете вставить название статьи в любое место , включив ссылку на примитив &title; – как для следующего элемента:

Механизм примитивов наиболее полезен при наличии часто используемых фрагментов XML -текста. Например, если название статьи многократно фигурирует по ее тексту, использование примитива (как в предыдущем примере) позволит сократить время набора, добиться однородности и облегчить внесение изменений в название. Вы можете изменить текст названия, встречающегося в различных листах статьи, просто отредактировав объявление примитива в DTD . Например:

Если вы знакомы с программированием, то легко уловите сходство между механизмом использования примитивов XML и определением констант в языках программирования (например, объявления с помощью инструкции #define в C).

Механизм примитивов также необходим при включении не XML -данных в XML -документ (например, графические данные для изображения).

Типы примитивов

Существует множество разновидностей примитивов. Материал, излагаемый в этом разделе, может показаться довольно абстрактным (прежде, чем вы познакомитесь с деталями и рассмотрите примеры), возвращение к этой информации впоследствии позволит значительно облегчить восприятие примитивов.

Примитивы классифицируются по трем признакам:

  • общие и параметрические. Общий примитив включает содержимое документа – т.е. XML-текст или другие текстовые или не текстовые данные, которые вы можете использовать внутри элемента Документ. Оба примера примитивов, рассмотренных в предыдущем разделе ( title и topics ) относятся к общим примитивам. Параметрический примитив содержит XML-текст, который может быть помещен в DTD. В спецификации XML термин примитив относится к общим примитивам;
  • внутренние и внешние. Внутренний примитив содержится внутри строки в кавычках (примитив title в предыдущем разделе). Внешний примитив содержится в отдельном файле (примитив topics в предыдущем разделе);
  • разбираемые или неразбираемые. Разбираемый примитив содержит XML-текст (символьные данные, разметка или то и другое). Когда вы вставляете ссылку на разбираемый примитив в документ, ссылка замещается содержимым примитива (замещающий текст), который становится составной частью документа. Синтаксический анализатор XML разбирает (сканирует) содержимое примитива точно так же, как он сканирует непосредственно введенный в документ текст. Оба примера примитивов, рассмотренных в предыдущем разделе ( title и topics ) являются разбираемыми примитивами.

Неразбираемый примитив может содержать любой тип данных: XML-данные или, что чаще, не XML-данные. Не XML-данные могут представлять собой либо текстовые данные (например, название) или не текстовые данные (например, графические данные для изображения). Поскольку неразбираемый примитив обычно не содержит XML, его содержимое нельзя непосредственно вставить в документ посредством ссылки на примитив. Тем не менее, вы можете связать с именем примитива атрибут типа ENTITY или ENTITIES , чтобы приложение получило доступ к имени примитива и его описанию, а также могло работать с его данными.

Поскольку примитивы классифицируются по этим трем признакам и в каждой классификации имеются две категории, теоретически существует восемь потенциальных типов примитивов, как показано на диаграмме (см. рис. 6.1).

Однако три типа примитивов из этих восьми в XML не поддерживаются (на диаграмме они зачеркнуты). Следовательно, реально в XML имеется только пять типов примитивов:

  • общие внутренние разбираемые;
  • общие внешние разбираемые;
  • общие внешние неразбираемые;
  • параметрические внутренние разбираемые;
  • параметрические внешние разбираемые.

О том, как определять и использовать их, вы и узнаете в этой лекции.

Лекция 5. Простые примитивы AutoCAD

Дата добавления: 2013-12-23 ; просмотров: 5127 ; Нарушение авторских прав

Режимы: шаг, сетка, орто, привязка, модель.

ШАГ и СЕТКА — самый простой способ точного построения элементов рисунка без явного ввода координат. Он позволяет привязывать объекты к узлам сетки с регулярным шагом. Но этот механизм можно применять только тогда, когда вводимые мышью точки рисунка попадают в узлы сетки, т.е. находятся на регулярных расстояниях друг от друга.кнопка ШАГ в строке состоянияили F9 на клавиатурекнопка СЕТКА в строке состоянияили F7 на клавиатуреОРТО —рисование только по вертикали или горизонтали¨ Кнопка ОРТО в строке состояния¨ F8 на клавиатуреПРИВЯЗКА — это механизм обеспечения точности построений, который позволяет привязываться к характерным точкам объектовОбъектная привязка — наиболее быстрый способ точно указать точку на объекте, не обязательно зная ее координаты, а также построить вспомогательные линии. Контрольные вопросы: 1. В чем заключается назначение и роль автоматизированных систем проектирования?2. Выдвигаются ли специальные требования к аппаратной и системной платформе со стороны AutoCAD?3. Перечислите элементы интерфейса AutoCA.4. Какими способами можно вызвать команду AutoCAD?5. Перечислите существующие режимы рисования в AutoCAD.6. Укажите главную особенность режима рисования ОРТО.7. В каких случаях удобно использовать шаговую привязку и сетку? Литература:

1. AutoCAD 2007 Руководство чертежника, конструктора, архитектора. Вернер Зоммер, перевод с немецкого Молявко С.М., Москва БИНОМ 2007

2. AutoCAD 2009 для студента. Самоучитель. – СПб. Питер, 2008

1. Типы примитивов: простые и сложные.2. Простые примитивы:a. Точкиb. Отрезкиc. Прямыеd. Окружностиe. Дугиf. Эллипсg. Сплайн Цель:изучить типы примитивов и простые примитивы AutoCAD1. Типы примитивов: простые и сложные.

Примитивы, применяемые в инженерной графике, можно разделить на простые и сложные.

Простыми примитивами будем называть следующие объекты: точка, отрезок, дуга, окружность, прямая, луч, эллипс, сплайн, однострочный текст, полоса, фигура.

Сложные примитивы – это те примитивы, которые можно путем специальной операции расчленения разложить на более простые. К сложным отнесем следующие объекты: полилиния, мультилиния, многострочный текст, таблица, размер, выноска, допуск, штриховка, вхождение блока, растровые изображения, маска, область. В сложные включим также такие примитивы, как внешняя ссылка и атрибут.

Все перечисленные выше примитивы используются в двумерной графике.

Операции построения большей части примитивов могут быть выполнены с помощью кнопок панели инструментов Рисовать (Draw).

2. Простые примитивы:a. Точки

Точки являются простейшими геометрическими объектами. Точки не имеют большого значения в системе AutoCAD, поскольку для создания, например, отрезка не обязательно заранее строить точки, которые являются его концами. Однако в ряде случаев (когда необходимо разделить объект на равнее части и т.п.) без точек все-таки не обойтись.


b. Отрезки Базовым примитивом в AutoCAD является линия.Команда LINE, формирующая отрезок, вызывается из падающего меню Черчение / Отрезок или щелчком на пиктограмме Отрезок на панели инструментов Черчение.Самый простой способ задания первой точки отрезка — указать ее с помощью мыши на видимой части графического экрана, а затем зафиксировать нажатием левой кнопки мыши. При выборе точки можно ориентироваться на счетчик координат в левом нижнем углу.Отрезки могут быть одиночными или объединенными в ломаную линию. Несмотря на то что сегменты соприкасаются в конечных точках, каждый из них представляет собой отдельный объект. Отрезки используются, если требуется работа с каждым сегментом в отдельности; если же необходимо, чтобы набор линейных сегментов представлял единый объект, лучше применять полилинии. Последовательность отрезков может быть замкнутой — в этом случае конец последнего сегмента совпадает с началом первого.c. Прямые

Отличие примитива прямая от отрезка в том, что прямая продлевается автоматически в обе стороны до границ экрана независимо от масштаба изображения.

Данная команда служит для проведения вспомогательных линий, например в качестве линий связи между проекциями детали.

d. Окружности

Команда Окружностьпозволяет вычертить окружность одним из шести способов (в скобках даны соответствующие пункты подменю Рисовать | Окружность):

· по центру окружности и ее радиусу (Центр, радиус (Center, Radius));

· по центру окружности и ее диаметру (Центр, диаметр (Center, Diameter));

· по двум точкам диаметра окружности (2 точки (2 Points));

· по трем точкам окружности (3 точки (3 Points));

· по двум касательным и радиусу (кас., кас., радиус (Tan, Tan, Radius));

· по трем касательным (кас., кас., кас. (Tan, Tan, Tan)).

e. Дуга

Дуга — это примитив, являющийся частью окружности.

В AutoCAD существуют разные способы задания дуги, например:

· начальной точкой, центром и конечной точкой;

· начальной точкой, конечной точкой и радиусом;

· центром, начальной точкой и длиной хорды и т.д.

f. Эллипс Имеется возможность строить эллипсы и эллиптические дуги. По умолчанию построение эллипсов производится путем указания начальной и конечной точек первой оси, а также половины длины второй оси. Самая длинная ось эллипса называется его большой осью, самая короткая — малой. Оси могут определяться в любом порядке.g. Сплайн Сплайны применяются для рисования кривых произвольной формы, например горизонталей в географических информационных системах или при проектировании автомобилей. Сплайн можно строить путем интерполяции по набору точек, через которые он должен проходить. Таким способом при построении кривых для двумерного и трехмерного моделирования достигается намного большая точность, чем при использовании полилиний. К тому же рисунок, использующий сплайны, занимает меньше места на диске и в оперативной памяти, чем рисунок с полилиниями. Контрольные вопросы: 1. Что относится к простым примитивам AutoCAD?2. Дайте характеристику самому простому примитиву AutoCAD — точке.3. Каково назначение линий и отрезков в AutoCAD?4. Какие существуют варианты вычерчивания окружностей?5. Перечислите способы рисования дуг.6. Как на практике используются сплайны? Литература:

1. AutoCAD 2007 Руководство чертежника, конструктора, архитектора. Вернер Зоммер, перевод с немецкого Молявко С.М., Москва БИНОМ 2007

2. AutoCAD 2009 для студента. Самоучитель. – СПб. Питер, 2008

Подсистемы и примитивы

API для PAM предоставляет шесть различных примитивов для аутентификации, сгруппированных в четыре подсистемы, каждая из которых описывается ниже.

Аутентификация. Эта подсистема, собственно говоря, реализует аутентификацию аппликанта и выяснение полномочий учётной записи. Она предоставляет два примитива:

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

Функция pam_setcred устанавливает полномочия учётной записи, такие, как идентификатор пользователя, членство в группах и ограничения на использование ресурсов.

Управление учётной записью. Эта подсистема обрабатывает вопросы доступности учетной записи, не связанные с аутентификацией, такие, как ограничения в доступе на основе времени суток или загрузки сервера. Он предоставляет единственный примитив:

Функция pam_acct_mgmt проверяет, доступна ли запрашиваемая учётная запись.

Управление сеансом. Эта подсистема отрабатывает задачи, связанные с установлением и закрытием сеанса, такие, как учет входов пользователей. Она предоставляет два примитива:

Функция pam_open_session выполняет действия, связанные с установлением сеанса: добавление записей в базы данных utmp и wtmp, запуск агента SSH и так далее.

Функция pam_close_session выполняет действия, связанные с закрытием сеанса: добавление записей в базы данных utmp и wtmp, завершение работы агента SSH и так далее.

Управление паролем. Эта подсистема используется для изменения ключа аутентификации, связанного с учетной записью, по причине истечения его срока действия или желания пользователя изменить его. Она предоставляет единственный примитив:

Функция pam_chauthtok изменяет ключ аутентификации, опционально проверяя, что он труден для подбора, не использовался ранее и так далее.

Цепочки и политики

Когда сервер инициирует PAM-транзакцию, библиотека PAM пытается загрузить политику для службы, указанной при вызове функции pam_start. Политика определяет, как должны обрабатываться запросы на аутентификацию, и задаётся в конфигурационном файле. Это составляет другую основополагающую концепцию PAM: возможность администратору настраивать политику безопасности системы (в самом широком её понимании) простым редактированием текстового файла.

Политика состоит из четырёх цепочек, по одной на каждый из методов PAM. Каждое звено представляет собой последовательность конфигурационных утверждений, задающих вызываемый модуль, некоторые (необязательные) параметры для передачи в модуль, и управляющий флаг, описывающий, как интерпретировать возвращаемый из модуля код.

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

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

Если модуль возвратил положительный ответ, выполняется оставшаяся часть цепочки, запрос удовлетворяется, если никакой другой модуль не отработает отрицательно. Если же модуль возвратит отрицательный ответ, остаток цепочки тоже отрабатывается, но запрос отвергается.

Если модуль возвращает положительный ответ, выполняется оставшаяся часть цепочки, запрос удовлетворяется, если никакой другой модуль не отработает отрицательно. Если же модуль отрабатывает отрицательно, то отработка цепочки немедленно прекращается, а запрос отвергается.

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

Модуль отрабатывается, но результат выполнения игнорируется. Если все модули в цепочке помечены как optional, то удовлетворяться будут все запросы.

Когда сервер вызывает один из шести PAM-примитивов, PAM запрашивает цепочку подсистемы, к которой принадлежит примитив, и запускает каждый модуль, перечисленный в цепочке в порядке их перечисления, пока список не будет исчерпан либо не будет определено, что дальнейшей обработки не нужно (по причине достижение модуля, вернувшего положительный ответ при условии binding или sufficient, либо отрицательный с условием requisite). Запрос подтверждается, если только был вызван по крайней мере один модуль, и все неопциональные модули вернули положительный ответ.

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

Примитивы и механизм доступа

В языке Java существует два типа переменных: примитивные, например int и boolean, а также ссылочные типы вроде Integer и Boolean (классы-обертки). Для каждого примитивного типа существует, соответствующий ему ссылочный тип.

Классы-обертки являются неизменяемыми: это означает, что после создания объекта его состояние (значение поля value) не может быть изменено; и задекларированы, как final
(от этих классов невозможно наследоваться).

Java автоматически производит преобразования между примитивными типами и их обертками:

В зависимости от реализации виртуальной машины, эти значения могут изменяться. Например, в виртуальной машине Oracle значения типа boolean сопоставляются со значениями 0 и 1 типа int (это связано с тем, что в VM нет инструкций для работы с булевыми значениями) и, как результат, занимают в памяти 32 бита.

Переменные примитивных типов хранятся в стеке, позволяя иметь к ним быстрый доступ.

Ссылочные переменные ссылаются на объекты, которые хранятся в куче, к ним мы имеем более медленный доступ (рекомендуем ознакомиться с понятиями Стек и Куча, для лучшего усвоения материала). Ссылочные типы имеют определенные накладные расходы относительно их примитивных аналогов.

Накладные расходы зависят от реализации конкретной JVM. Здесь мы приведем результаты для 64-х битной виртуальной машины со следующими параметрами:

Синхронизация

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

Прежде чем приступить к исследованиям, давайте обсудим саму необходимость синхронизации при работе с данными маленького объема. Современные процессоры способны выполнять атомарные операции чтения и записи содержимого в памяти. Например, запись 32-разрядного целого числа всегда выполняется атомарно. Это означает, что если процессор записывает в ячейку памяти значение 0xDE178AAC, прежде инициализированную нулем, другой процессор никогда не получит частично измененное значение в этой ячейке, такое как 0xDE170000 или 0x00008AAC. К сожалению, то же самое нельзя сказать о более объемных данных; например, даже на 64-разрядном процессоре операция записи 20 байт не является атомарной и не может быть атомарной.

Всякий раз, когда для выполнения операции с областью памяти требуется выполнить несколько инструкций, немедленно возникает проблема синхронизации. Например, операция ++i (где i является переменной на стеке типа int) обычно транслируется в последовательность из трех машинных инструкций:

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

В этом случае переменная получит значение 101, даже при том, что операция инкремента была выполнена двумя процессорами и переменная должна была получить значение 102. Это состояние гонки за ресурсами (race condition) — мы надеемся, очевидно и легко обнаруживается, — является наглядным примером ситуаций, требующих синхронизации.

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

Илон Маск рекомендует:  Что такое код sesam_affected_rows

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

Языки программирования, основанные на использовании модели агентов, интегрируют модель конкурентного доступа глубоко в язык и требуют организации явных взаимодействий между агентами (объектами) в терминах обмена сообщениями, а не операций с совместно используемой памятью.

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

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

Код без блокировок

Один из подходов к синхронизации основан на перемещении этого бремени в операционную систему. В конце концов, операционная система предоставляет средства для создания потоков и управления ими, и принимает на себя всю ответственность за их выполнение. Поэтому вполне естественно ожидать, что система предоставит комплект примитивов синхронизации. Чуть ниже мы обсудим механизмы синхронизации, имеющиеся в Windows, но при таком подходе возникает вопрос, как операционная система реализует эти механизмы?

Конечно, ОС Windows сама нуждается в синхронизации доступа к своим внутренним структурам данных — даже к структурам данных, представляющим другие механизмы синхронизации — и не может реализовать механизмы синхронизации рекурсивно. Кроме того, как оказывается, механизмы синхронизации Windows часто требуют выполнения системных вызовов (что связано с переходом из режима пользователя в режим ядра), в результате чего происходит переключение контекста потока, что является слишком дорогим удовольствием, если операция, требующая синхронизации, достаточно дешева (например, увеличение числового значения или добавление элемента в связанный список).

Все семейства процессоров, на которых Windows может выполняться, поддерживают аппаратный примитив синхронизации с названием «Сравнить-и-Заменить» (Compare-And-Swap, CAS). Примитив CAS выполняет операцию атомарно и имеет следующую семантику (в псевдокоде):

Проще говоря, примитив CAS сравнивает содержимое памяти по адресу location с указанным значением comparand. Если в памяти хранится это значение, оно заменяется другим значением value; в противном случае значение в памяти не изменяется. В любом случае возвращается прежнее содержимое памяти, хранившееся до операции.

В процессорах Intel x86 этот примитив реализован в виде инструкции LOCK CMPXCHG. Трансляция вызова CAS(&a, b, с) в инструкцию LOCK CMPXCHG — это чисто механическая процедура, именно поэтому мы будем использовать аббревиатуру CAS. В .NET Framework примитив CAS реализован в виде множества перегруженных методов Interlocked.CompareExchange():

Единственной CAS-операции часто недостаточно, чтобы обеспечить надежную синхронизацию, если только не требуется выполнить единственную операцию проверки с заменой. Однако в комбинации с конструкцией цикла примитив CAS может с успехом использоваться для решения самых разных задач синхронизации.


Для начала рассмотрим простой пример умножения на месте. Нам требуется атомарно выполнить операцию x* = y, где x является совместно используемой переменной, запись в которую может выполняться одновременно несколькими потоками, а y — это константа, недоступная для изменения. Ниже приводится метод на языке C#, решающий поставленную задачу с применением примитива CAS:

Каждая итерация начинается с чтения значения x во временную переменную на стеке, которая недоступна другим потокам. Затем вычисляется результат умножения для записи в переменную х. И, наконец, цикл завершается, если compareExchange сообщит, что замена прежнего значения x результатом умножения произведена успешно, вернув оригинальное значение. Мы не можем гарантировать, что цикл завершится за некоторое ограниченное число итераций; однако весьма маловероятно, даже при наличии других процессоров, цикл будет выполнен более чем несколько раз. Но, как бы то ни было, цикл готов к такой ситуации.

Взгляните на следующую историю выполнения цикла двумя процессорами со значениями x = 3, y = 5:

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

Почему? Двукратное чтение значения x, даже в такой быстрой последовательности, не гарантирует, что будет получено одно и то же значение! Следующая история выполнения показывает, как могут быть получены неправильные результаты на двух процессорах и начальных значениях x = 3, y = 5 — в конце выполнения получится результата x = 60!

Этот результат можно обобщить на любой алгоритм, где требуется прочитать единственное значение из памяти и заменить его новым, независимо от его сложности. Ниже приводится обобщенная версия:

Операция умножения достаточно легко выражается в терминах обобщенной версии:

С помощью примитива CAS можно реализовать простой механизм синхронизации, который называется . Идея состоит в следующем: как только блокировка приобретается каким-то одним потоком, все другие потоки должны терпеть неудачу при попытке захватить ее, и повторять попытки. Циклическая блокировка может быть приобретена единственным потоком, а все остальные потоки должны будут «крутиться» (spin) в ожидании ее освобождения (понапрасну тратя процессорное время):

Модели памяти и изменчивые переменные

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

Вообще говоря, модель памяти для конкретного языка/окружения описывает, как компилятор и процессор могут переупорядочивать операции, выполняемые разными потоками, влияющими на взаимодействие потоков посредством совместно используемой памяти. Хотя в большинстве моделей принимается, что операции чтения и записи с одной и той же областью памяти не могут переупорядочиваться, существует редко встречающееся соглашение о семантике операций чтения и записи, выполняемых с разными участками памяти. Например, следующая программа может вывести 13 при начальных значениях f = 0, x = 13:

Причина такого, казалось бы, неожиданного результата состоит в том, что компилятор и процессор могут изменить порядок выполнения инструкций процессором 2 так, что запись в переменную f будет выполнена до записи в переменную x, а порядок выполнения инструкций процессором 1 так, что чтение переменной x будет выполнено перед чтением переменной f. Неправильное понимание конкретной модели памяти может приводить к чрезвычайно тяжело выявляемым ошибкам.

В C# имеется несколько средств, которые можно использовать для предупреждения проблем, связанных с переупорядочением операций. Первое из них — ключевое слово volatile, которое препятствует переупорядочению операций с конкретной переменной компилятором и большинством процессоров.

Второе — множество методов класса Interlocked и метод Thread.MemoryBarrier(), устанавливающие барьер, который не может быть преодолен в каком-то одном или в обоих направлениях при попытке переупорядочить инструкции. К счастью, механизмы синхронизации ОС Windows (вовлекающие системные вызовы), а также примитивы синхронизации без блокировок (lock-free) в TPL, автоматически устанавливают барьеры, когда это необходимо. Однако, если вы собираетесь заняться реализацией собственного механизма синхронизации, вам придется потратить немало времени, чтобы разобраться в модели памяти целевой среды выполнения.

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

Итак, вернемся к классу SpinLock. В нашей реализации циклической блокировки значение 0 соответствует свободной блокировке, а 1 — занятой. Наша реализация пытается заменить внутреннее значение единицей, передавая значение 0 для сравнения — то есть, блокировка может быть приобретена, только когда она свободна. Поскольку нет никаких гарантий, что поток, получивший блокировку, быстро освободит ее, использование циклической блокировки означает, что множество других потоков могут «крутиться» на месте, в ожидании освобождения блокировки, и напрасно расходовать процессорное время.

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

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

Циклическая блокировка не справедлива в терминах семантики FIFO. Процессор может быть последним из десяти процессоров, вызвавших метод Acquire(), но получить блокировку первым.

Освобождение циклической блокировки вызывает актуализацию кешей всех процессоров, вращающихся внутри метода Acquire(), хотя только один процессор сможет приобрести ее.

Ядро Windows использует циклические блокировки с очередью (in-stack queued spinlocks); циклическая блокировка с очередью поддерживает очередь процессоров, ожидающих ее освобождения, и каждый процессор, ожидающий на блокировке, «вращается» вокруг отдельной ячейки памяти, которая не кешируется другими процессорами. Когда процессор, владевший блокировкой, освобождает ее, он находит первый процессор в очереди и устанавливает бит, появление которого ожидает данный процессор. Это гарантирует семантику FIFO очереди и предотвращает принудительную актуализацию кешей всех процессоров, кроме того, который благополучно приобрел блокировку.

Реализации циклических блокировок промышленного уровня могут быть еще более надежными, предусматривать возможность определения предельного времени ожидания (за счет преобразования цикла в блокирующее ожидание), следить за потоком-владельцем, чтобы обеспечить корректное приобретение и освобождение, позволять рекурсивное приобретение блокировок и поддерживать дополнительные удобства. Одной из рекомендуемых реализаций является тип SpinLock из библиотеки Task Parallel Library.

Имея на вооружении примитив синхронизации CAS, мы можем реализовать чудо инженерной мысли — стек без блокировок. При обсуждении коллекций мы уже познакомились с некоторыми параллельными коллекциями, поэтому не будем повторять обсуждение, а реализуем тип ConcurrentStack , оставшийся для нас тайной. Как по волшебству, стек типа ConcurrentStack позволяет нескольким потокам вталкивать и выталкивать элементы, не требуя использовать механизмы синхронизации (которые мы рассмотрим далее).

Реализацию стека без блокировки мы выполним на основе односвязного списка. Вершиной стека будет голова списка; операции вталкивания элемента в стек и выталкивания со стека будут реализованы как замена головы списка. Для синхронизации этих операций мы используем примитив CAS; фактически мы можем использовать вспомогательный метод DoWithCAS , представленный выше:

Метод Push() пытается заменить голову списка новым узлом, чей указатель Next будет указывать на текущую голову списка. Аналогично метод TryPop() пытается заменить голову списка узлом, на который ссылается указатель Next текущей головы, как показано на рисунке ниже:

Кому-то может показаться, что с помощью CAS и похожих примитивов синхронизации можно реализовать любую структуру данных, и действительно, мы можем привести примеры коллекций без блокировок, широко используемых в настоящее время:

двусвязный список без блокировки;

очередь без блокировки (с головой и хвостом);

простая очередь с поддержкой приоритетов.

Однако существует множество разнообразных коллекций, которые не могут быть реализованы без блокировок и вынуждающих использовать блокирующие механизмы синхронизации. Кроме того, существует масса ситуаций, требующих использовать синхронизацию, но не позволяющих применять примитив CAS, потому что приходится выполнять продолжительные операции под защитой блокировки. Теперь обратимся к «настоящим» механизмам синхронизации, реализуемым операционной системой.

Механизмы синхронизации Windows

ОС Windows предлагает множество механизмов синхронизации для использования в программах, выполняющихся в пользовательском режиме, таких как события, семафоры, мьютексы и переменные условий (condition variables). Все эти механизмы доступны программам посредством дескрипторов и функций Win32 API, которые обращаются к системным вызовам от нашего имени.

Платформа .NET Framework обертывает большинство механизмов синхронизации Windows тонкими объектно-ориентированными обертками, такими как классы ManualResetEvent, Mutex, Semaphore и другими. Поверх имеющихся механизмов синхронизации .NET Framework предлагает несколько новых, таких как ReaderWriterLockSlim и Monitor. Мы не будем подробно исследовать каждый из механизмов синхронизации, более подробно они описаны в разделе «Потоки и файлы», а далее займемся более важным для нас делом — изучением характеристик производительности.

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

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

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

Механизмы синхронизации ОС Windows и .NET доступны приложениям в первую очередь в терминах семантики приобретения и освобождения, также известной как семантика сигнального состояния (signal state). Когда механизм синхронизации взводится в сигнальное состояние, он пробуждает поток (или группу потоков), ожидающих освобождения блокировки. В таблице ниже описывается семантика состояния сигнала для некоторых из механизмов синхронизации, доступных в настоящее время приложениям для .NET:

Семантика состояния сигнала для некоторых механизмов синхронизации

Механизм синхронизации Когда переходит в сигнальное состояние? Какие потоки пробуждаются?
Mutex Когда поток вызывает Mutex.ReleaseMutex() Один из потоков, ожидающих на мьютексе
Semaphore Когда поток вызывает Semaphore.Release() Один из потоков, ожидающих на семафоре
ManualResetEvent Когда поток вызывает ManualResetEvent.Set() Все потоки, ожидающие событие
AutoResetEvent Когда поток вызывает AutoResetEvent.Set() Один из потоков, ожидающих событие
Monitor Когда поток вызывает Monitor.Exit() Один из потоков, ожидающих на мониторе
Barrier Когда поток вызывает Barrier.SignalAndWait() Все потоки, ожидающие на барьере
ReaderWriterLock для чтения Когда не остается пишущих потоков или когда последний пишущий поток освобождает блокировку для записи Все потоки, ожидающие возможности приобрести блокировку для чтения
ReaderWriterLock для записи Когда не остается ни пишущих, ни читающих потоков Все потоки, ожидающие возможности приобрести блокировку для записи

Помимо семантик, отличных от семантики сигнального состояния, некоторые механизмы синхронизации отличаются также внутренней реализацией.

Например, критические секции Win32 и мониторы CLR реализуют оптимизированные блокировки. При попытке приобрести такую блокировку, доступную в данный момент, поток может получить ее сразу, без обращения к системному вызову. Имеется также семейство механизмов синхронизации, реализующих блокировки для чтения/записи, различающих попытки доступа для чтения и для записи и обеспечивающих более высокую масштабируемость, когда чтение данных выполняется значительно чаще записи.

Выбор подходящего механизма синхронизации из предлагаемых ОС Windows и .NET зачастую сделать очень непросто, а иногда более высокую производительность или удобную семантику можно получить, реализовав собственный механизм синхронизации. На этом мы заканчиваем исследование механизмов синхронизации; вам решать какой механизм синхронизации выбрать — на основе примитивов синхронизации без блокировок или на основе блокировок, и какая комбинация механизмов лучше соответствует вашему приложению.

Никакое обсуждение механизмов синхронизации не может считаться полным без перечисления структур данных (коллекций), изначально предназначенных для использования в многопоточной среде. Такие коллекции являются потокобезопасными — могут совместно использоваться несколькими потоками — и масштабируемыми, не вызывающими непомерное снижение производительности из-за использования блокировок.

Вопросы оптимального использования кеша

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

Для начала исследуем следующий последовательный метод. Он суммирует элементы двумерного массива целых чисел и возвращает результат:

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

Выполнив каждый из методов 25 раз в системе с процессором Intel Core i7, мы получили следующие результаты для матрицы а 2000 x 2000: среднее время выполнения последовательного метода составило 325 мсек, а параллельного метода 935 мсек, в три раза медленнее последовательной версии!

Понятно, что это совершенно неприемлемо, но почему так получилось? Эта ситуация не может служить еще одним примером слишком мелкого дробления задачи, потому что было запущено всего 4 потока. Если предположить, что проблема имеет некоторое отношение к кешу процессора (хотя бы потому, что пример приводится в разделе с названием «Вопросы оптимального использования кеша»), имеет смысл исследовать количество промахов кеша в каждом из двух методов. Профилировщик Visual Studio (с частотой срабатывания 2000 раз в секунду) сообщил о 963 промахах в параллельной версии и только о 659 промахах в последовательной; подавляющее большинство промахов было обнаружено в теле внутреннего цикла, выполняющем чтение элемента матрицы.

И снова, почему? Почему запись в массив localSums порождает промахов больше, чем запись в локальную переменную? Ответ прост: дело в том, что запись в совместно используемый массив вызывает необходимость актуализации строк кеша в других процессорах, что в каждой операции += приводит к промаху кеша.

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

В примере выше весьма вероятно, что массив localSums целиком уместится в одну строку кеша, и одновременно в кешах всех четырех процессоров, выполняющих потоки приложения. Каждая операция записи в этот массив любым из процессоров будет вызывать необходимость актуализации строки кеша во всех четырех процессорах, приводя к постоянному обновлению кешей:

На рисунке видно, что процессор 1 записывает значение в localSums[1], а процессор 2 записывает значение в localSums[2]. Так как оба элемента массива находятся в смежных ячейках памяти и попадают в одну строку кеша в кешах обоих процессоров, каждая операция записи вызывает необходимость актуализации кеша другого процессора.

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

Проблема актуализации кеша — очень неприятная и исключительно сложно поддается выявлению в реальных приложениях, даже с помощью мощных профилировщиков. Понимание причин, ее порождающих, и применение приемов профилактики при проектировании вычислительных алгоритмов поможет вам сэкономить массу времени позже.

Я столкнулся с похожей ситуацией в промышленном приложении, которое распределяло задания между двумя потоками, выполняющимися на двух процессорах, с применением общей очереди. После внесения незначительных изменений во внутреннюю структуру полей класса очереди обнаружилось существенное падение производительности (примерно 20%). В ходе скрупулезных исследований выяснилось, что падение производительности было вызвано переупорядочением полей в классе очереди; два поля, запись в которые выполняются разными потоками, оказались слишком близко друг к другу и попали в одну строку кеша. После разнесения полей, производительность очереди восстановилась до приемлемого уровня.

Лекция 5. Простые примитивы AutoCAD

Дата добавления: 2013-12-23 ; просмотров: 5128 ; Нарушение авторских прав

Режимы: шаг, сетка, орто, привязка, модель.

ШАГ и СЕТКА — самый простой способ точного построения элементов рисунка без явного ввода координат. Он позволяет привязывать объекты к узлам сетки с регулярным шагом. Но этот механизм можно применять только тогда, когда вводимые мышью точки рисунка попадают в узлы сетки, т.е. находятся на регулярных расстояниях друг от друга.кнопка ШАГ в строке состоянияили F9 на клавиатурекнопка СЕТКА в строке состоянияили F7 на клавиатуреОРТО —рисование только по вертикали или горизонтали¨ Кнопка ОРТО в строке состояния¨ F8 на клавиатуреПРИВЯЗКА — это механизм обеспечения точности построений, который позволяет привязываться к характерным точкам объектовОбъектная привязка — наиболее быстрый способ точно указать точку на объекте, не обязательно зная ее координаты, а также построить вспомогательные линии. Контрольные вопросы: 1. В чем заключается назначение и роль автоматизированных систем проектирования?2. Выдвигаются ли специальные требования к аппаратной и системной платформе со стороны AutoCAD?3. Перечислите элементы интерфейса AutoCA.4. Какими способами можно вызвать команду AutoCAD?5. Перечислите существующие режимы рисования в AutoCAD.6. Укажите главную особенность режима рисования ОРТО.7. В каких случаях удобно использовать шаговую привязку и сетку? Литература:

1. AutoCAD 2007 Руководство чертежника, конструктора, архитектора. Вернер Зоммер, перевод с немецкого Молявко С.М., Москва БИНОМ 2007

2. AutoCAD 2009 для студента. Самоучитель. – СПб. Питер, 2008

1. Типы примитивов: простые и сложные.2. Простые примитивы:a. Точкиb. Отрезкиc. Прямыеd. Окружностиe. Дугиf. Эллипсg. Сплайн Цель:изучить типы примитивов и простые примитивы AutoCAD1. Типы примитивов: простые и сложные.

Примитивы, применяемые в инженерной графике, можно разделить на простые и сложные.

Простыми примитивами будем называть следующие объекты: точка, отрезок, дуга, окружность, прямая, луч, эллипс, сплайн, однострочный текст, полоса, фигура.

Сложные примитивы – это те примитивы, которые можно путем специальной операции расчленения разложить на более простые. К сложным отнесем следующие объекты: полилиния, мультилиния, многострочный текст, таблица, размер, выноска, допуск, штриховка, вхождение блока, растровые изображения, маска, область. В сложные включим также такие примитивы, как внешняя ссылка и атрибут.

Все перечисленные выше примитивы используются в двумерной графике.

Операции построения большей части примитивов могут быть выполнены с помощью кнопок панели инструментов Рисовать (Draw).

2. Простые примитивы:a. Точки

Точки являются простейшими геометрическими объектами. Точки не имеют большого значения в системе AutoCAD, поскольку для создания, например, отрезка не обязательно заранее строить точки, которые являются его концами. Однако в ряде случаев (когда необходимо разделить объект на равнее части и т.п.) без точек все-таки не обойтись.

b. Отрезки Базовым примитивом в AutoCAD является линия.Команда LINE, формирующая отрезок, вызывается из падающего меню Черчение / Отрезок или щелчком на пиктограмме Отрезок на панели инструментов Черчение.Самый простой способ задания первой точки отрезка — указать ее с помощью мыши на видимой части графического экрана, а затем зафиксировать нажатием левой кнопки мыши. При выборе точки можно ориентироваться на счетчик координат в левом нижнем углу.Отрезки могут быть одиночными или объединенными в ломаную линию. Несмотря на то что сегменты соприкасаются в конечных точках, каждый из них представляет собой отдельный объект. Отрезки используются, если требуется работа с каждым сегментом в отдельности; если же необходимо, чтобы набор линейных сегментов представлял единый объект, лучше применять полилинии. Последовательность отрезков может быть замкнутой — в этом случае конец последнего сегмента совпадает с началом первого.c. Прямые

Отличие примитива прямая от отрезка в том, что прямая продлевается автоматически в обе стороны до границ экрана независимо от масштаба изображения.

Данная команда служит для проведения вспомогательных линий, например в качестве линий связи между проекциями детали.

d. Окружности

Команда Окружностьпозволяет вычертить окружность одним из шести способов (в скобках даны соответствующие пункты подменю Рисовать | Окружность):

· по центру окружности и ее радиусу (Центр, радиус (Center, Radius));

· по центру окружности и ее диаметру (Центр, диаметр (Center, Diameter));

· по двум точкам диаметра окружности (2 точки (2 Points));

· по трем точкам окружности (3 точки (3 Points));

· по двум касательным и радиусу (кас., кас., радиус (Tan, Tan, Radius));

· по трем касательным (кас., кас., кас. (Tan, Tan, Tan)).

e. Дуга

Дуга — это примитив, являющийся частью окружности.

В AutoCAD существуют разные способы задания дуги, например:

· начальной точкой, центром и конечной точкой;

· начальной точкой, конечной точкой и радиусом;

· центром, начальной точкой и длиной хорды и т.д.

f. Эллипс Имеется возможность строить эллипсы и эллиптические дуги. По умолчанию построение эллипсов производится путем указания начальной и конечной точек первой оси, а также половины длины второй оси. Самая длинная ось эллипса называется его большой осью, самая короткая — малой. Оси могут определяться в любом порядке.g. Сплайн Сплайны применяются для рисования кривых произвольной формы, например горизонталей в географических информационных системах или при проектировании автомобилей. Сплайн можно строить путем интерполяции по набору точек, через которые он должен проходить. Таким способом при построении кривых для двумерного и трехмерного моделирования достигается намного большая точность, чем при использовании полилиний. К тому же рисунок, использующий сплайны, занимает меньше места на диске и в оперативной памяти, чем рисунок с полилиниями. Контрольные вопросы: 1. Что относится к простым примитивам AutoCAD?2. Дайте характеристику самому простому примитиву AutoCAD — точке.3. Каково назначение линий и отрезков в AutoCAD?4. Какие существуют варианты вычерчивания окружностей?5. Перечислите способы рисования дуг.6. Как на практике используются сплайны? Литература:

1. AutoCAD 2007 Руководство чертежника, конструктора, архитектора. Вернер Зоммер, перевод с немецкого Молявко С.М., Москва БИНОМ 2007

2. AutoCAD 2009 для студента. Самоучитель. – СПб. Питер, 2008

Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL