СОДЕРЖАНИЕ
Введение
1. Механизмы параллельных вычислений в Windows
1.1. Особенности организации параллельных вычислений .
1.1.1. Оптимизация параллельных вычислений
1.2. Модели параллельных вычислений
1.2.1. Модель процесс/канал .
1.2.2. Модель обмен сообщениями
1.2.3. Модель параллелизм данных .
1.2.4. Модель общая память
1.3. Система параллельного программирования Linda .
2. Разработка справочной системы
2.1. Вызов справки
2.2. Рисование графических примитивов .
2.3. Интерфейс программы .
2.4. Требования к ПК
Вывод
Список используемых источников
Приложение А .
Приложение Б
РАЗДЕЛ 1
МЕХАНИЗМЫ ПАРАЛЛЕЛЬНЫХ ВЫЧИСЛЕНИЙ В WINDOWS
История развития вычислительных систем с массовым параллелизмом насчитывает уже не один десяток лет. Пожалуй, это одна из немногих областей науки и техники, где отечественные разработки находятся на уровне мировых достижений, а в отдельных случаях и превосходят их. Не стали исключением и супервычислители, используемые для построения нейрокомпьютеров.
Нейронная сеть — это сеть с конечным числом слоев из однотипных элементов — аналогов нейронов с различными типами связи между слоями. Элементарным строительным блоком нейронной сети является нейрон, осуществляющий взвешенное суммирование поступающих на его вход сигналов. Результат такого суммирования образует промежуточный выходной сигнал, который преобразуется активационной функцией в выходной сигнал нейрона. Среди основных преимуществ нейронной сети: инвариантность методов ее синтеза к размерности пространства признаков и размерам нейронной сети, адекватность перспективным технологиям, отказоустойчивость в смысле монотонного, а не катастрофического изменения качества решения задачи в зависимости от числа вышедших из строя элементов [1-3].
Нейрокомпьютер — это вычислительная система с параллельными потоками одинаковых команд и множественным потоком данных. Для большей ясности будем считать, что нейросетевые системы, реализованные программно на типовых ПК, относятся к нейроэмуляторам, на программном уровне реализующим типовые нейрооперации (взвешенное суммирование и нелинейное преобразование). Нейросетевые системы, реализованные в виде плат расширения стандартных вычислительных систем, будем называть нейроускорителями (взвешенное суммирование, как правило, реализуется аппаратно, например, на основе трансверсальных фильтров, а нелинейные преобразования — программно). Системы, реализованные в виде функционально законченных специализированных вычислительных устройств, следует относить к нейрокомпьютерам. Нейрокомпьютеры являются вычислительными системами с высоким параллелизмом, реализуемым на основе специализированной элементной базы, ориентированной на выполнение нейросетевых операций в нейросетевом логическом базисе.
Эффективное применение нейрокомпьютеров характерно, в частности, для случаев, требующих резкого сокращения времени обработки при решении пространственных задач повышенной размерности, которые во множестве можно найти практически в любой области: обработка изображений, выделение и слежение за движущимися объектами, задачи распознавания и классификации.
1.1. Особенности организации параллельных вычислений
При параллельных вычислениях необходимо программировать специальные действия по координации работы задач, а также следует четко определить "область деятельности" для каждой задачи. Рассмотрим здесь несколько возможных подходов для решения этих проблем.
При первом варианте организации параллельных вычислений все задачи запускаются одной командой, в которой указывается имя запускаемого исполняемого файла, число запускаемых задач, а также число и тип используемых процессоров. По этой команде запускаются на указанных процессорах требуемое число копий указанного исполняемого файла. Следовательно, программные коды всех запущенных в PVM задач в данном случае одинаковы. Для того чтобы эти задачи могли выполнять разные действия, им должен быть известен признак, отличающий каждую задачу от остальных. Тогда, используя этот признак в условных операторах, легко запрограммировать выполнение задачами разных действий. Наличие такого признака предусмотрено в любой многозадачной операционной системе. Это так называемый идентификатор задачи - целое число, которое присваивается задаче при запуске. Существенно, что при запуске задача получает идентификатор, отличный от идентификаторов задач, выполняемых в данное время. Это гарантирует, что идентификаторы всех запущенных задач в PVM будут различными. Если теперь обеспечить задачи возможностью определять собственный идентификатор и обмениваться информацией с другими задачами, то ясно, что им легко распределить между собой вычислительную работу, в зависимости, например, от занимаемого места в упорядоченном наборе идентификаторов задач.
Во втором обычно используемом варианте запуска задач сначала запускается одна задача (master), которая в коллективе задач будет играть функции координатора работ. Эта задача производит некоторые подготовительные действия, после чего запускает остальные задачи (slaves), которым может соответствовать либо тот же исполняемый файл, либо разные исполняемые файлы. Такой вариант организации параллельных вычислений предпочтительнее при усложнении логики управления вычислительным процессом, а также когда алгоритмы, реализованные в разных задачах, существенно различаются или имеется большой объем операций (например, ввода - вывода), которые обслуживают вычислительный процесс в целом.
1.1.1. Оптимизация параллельных вычислений
Главным критерием качества распараллеливания вычислений является сокращение общего времени решения задачи. Для простоты в качестве задач будем рассматривать здесь вычисления по формулам, в которых все алгебраические операции выполняются за одинаковое время T, а используемые процессоры все имеют одинаковые характеристики.
Пусть требуется вычислить величины
Y1 = A * B + C * D Y2 = (A + B) * C + D.
При использовании одного процессора Y1 и Y2 будут вычислены за одинаковое время 3T. При использовании двух процессоров Y1 может быть вычислено за время 2T, т.к. операции умножения могут быть выполнены параллельно. А вычисление Y2 не может быть ускорено, т.к. сама формула не допускает параллельного выполнения операций.
Из рассмотренного примера следует, что возможности для распараллеливания вычислений ограничиваются не только числом имеющихся процессоров, но и особенностями вычислительного алгоритма, который может вообще не допускать распараллеливания. Кроме того, ясно, что предельный эффект от использования N процессоров может быть достигнут лишь тогда, когда общая вычислительная нагрузка может быть разделена точно на N частей, и при этом ни один из процессоров не простаивает от начала и до конца вычислений.
Теперь обратим внимание на то, что в рассмотренном примере были проигнорированы затраты времени на пересылки данных между процессорами. Это отчасти правомерно, если процессоры используют общую память (следует отметить, что все процессоры имеют индивидуальную регистровую память гораздо более быстродействующую, чем ОЗУ). Если же процессоры работают с данными, хранящимися в индивидуальных ОЗУ, то обмен данными между этими ОЗУ снижает эффект от распараллеливания вычислений вплоть до того, что этот эффект может стать отрицательным. Отсюда следует, что при оптимизации распараллеливания вычислений нужно учитывать время, затрачиваемое на обмен данными между процессорами. И вообще при прочих равных условиях уменьшение числа и объемов сообщений, которыми обмениваются параллельно работающие процессоры, как правило, приводит к сокращению общего времени решения задачи. Поэтому желательно распараллеливать вычислительный процесс на уровне как можно более крупных блоков алгоритма.
До сих пор мы рассматривали вычисления, производимые над одной порцией исходных данных. При этом распараллеливание базируется на декомпозиции алгоритма вычислений. Более богатые возможности для распараллеливания открываются при многократном использовании формулы для потока входных данных. При этом, как правило, удается достичь максимального эффекта от распараллеливания вычислений, что видно на примере вычислений по формулам для Y1 и Y2.
Пусть каждые T секунд для вычисления очередного значения Y1 поступает новая порция исходных данных: A, B, C, D - и каждые T секунд процессор 1 и процессор 2 параллельно выполняют операции умножения, а процессор 3 в это время складывает произведения, полученные в предыдущие T секунд. Очевидно, что с увеличением массива исходных данных эффект от распараллеливания стремится к предельному значению. Более того, почти такой же эффект получается при вычислении Y2. Правда, здесь каждая порция исходных данных будет преобразовываться в результат уже в течение 3T секунд, зато в работе одновременно будут находиться не 2, а 3 порции исходных данных.
Распараллеливание вычислений по потоку данных лежит в основе так называемых конвейерных вычислений и часто позволяет добиться большего эффекта, чем распараллеливание, основанное на декомпозиции алгоритма. Поэтому там, где это возможно, его желательно использовать в первую очередь.
1.2. Модели параллельных вычислений
Параллельное программирование представляет дополнительные источники сложности - необходимо явно управлять работой тысяч процессоров, координировать миллионы межпроцессорных взаимодействий. Для того решить задачу на параллельном компьютере, необходимо распределить вычисления между процессорами системы, так чтобы каждый процессор был занят решением части задачи. Кроме того, желательно, чтобы как можно меньший объем данных пересылался между процессорами, поскольку коммуникации значительно больше медленные операции, чем вычисления. Часто, возникают конфликты между степенью распараллеливания и объемом коммуникаций, то есть чем между большим числом процессоров распределена задача, тем больший объем данных необходимо пересылать между ними. Среда параллельного программирования должна обеспечивать адекватное управление распределением и коммуникациями данных.
Из-за сложности параллельных компьютеров и их существенного отличия от традиционных однопроцессорных компьютеров нельзя просто воспользоваться традиционными языками программирования и ожидать получения хорошей производительности. Рассмотрим основные модели параллельного программирования, их абстракции адекватные и полезные в параллельном программировании:
Процесс/канал (Process/Channel)
В этой модели программы состоят из одного или более процессов, распределенных по процессорам. Процессы выполняются одновременно, их число может измениться в течение времени выполнения программы. Процессы обмениваются данными через каналы, которые представляют собой однонаправленные коммуникационные линии, соединяющие только два процесса. Каналы можно создавать и удалять.
Обмен сообщениями (Message Passing)
В этой модели программы, возможно различные, написанные на традиционном последовательном языке исполняются процессорами компьютера. Каждая программа имеют доступ к памяти исполняющего е§ процессора. Программы обмениваются между собой данными, используя подпрограммы приема/передачи данных некоторой коммуникационной системы. Программы, использующие обмен сообщениями, могут выполняться только на MIMD компьютерах.
Параллелизм данных (Data Parallel)
В этой модели единственная программа задает распределение данных между всеми процессорами компьютера и операции над ними. Распределяемыми данными обычно являются массивы. Как правило, языки программирования, поддерживающие данную модель, допускают операции над массивами, позволяют использовать в выражениях целые массивы, вырезки из массивов. Распараллеливание операций над массивами, циклов обработки массивов позволяет увеличить производительность программы. Компилятор отвечает за генерацию кода, осуществляющего распределение элементов массивов и вычислений между процессорами. Каждый процессор отвечает за то подмножество элементов массива, которое расположено в его локальной памяти. Программы с параллелизмом данных могут быть оттранслированы и исполнены как на MIMD, так и на SIMD компьютерах.
Общей памяти (Shared Memory)
В этой модели все процессы совместно используют общее адресное пространство. Процессы асинхронно обращаются к общей памяти как с запросами на чтение, так и с запросами на запись, что создает проблемы при выборе момента, когда можно будет поместить данные в память, когда можно будет удалить их. Для управления доступом к общей памяти используются стандартные механизмы синхронизации - семафоры и блокировки процессов.
1.2.1. Модель процесс/канал
Модель процесс/канал характеризуется следующими свойствами:
Параллельное вычисление состоит из одного или более одновременно исполняющихся процессов, число которых может изменяться в течение времени выполнения программы.
Процесс - это последовательная программа с локальными данными. Процесс имеет входные и выходные порты, которые служит интерфейсом к среде процесса.
В дополнение к обычным операциям процесс может выполнять следующие действия: послать сообщение через выходной порт, получить сообщение из входного порта, создать новый процесс и завершить процесс.
Посылающаяся операция асинхронная - она завершается сразу, не ожидая того, когда данные будут получены. Получающаяся операция синхронная: она блокирует процесс до момента поступления сообщения.
Пары из входного и выходного портов соединяются очередями сообщений, называемыми каналами (channels). Каналы можно создавать и удалять. Ссылки на каналы (порты) можно включать в сообщения, так что связность может измениться динамически.
Процессы можно распределять по физическим процессорам произвольным способами, причем используемое отображение (распределение) не воздействует на семантику программы. В частности, множество процессов можно отобразить на одиночный процессор.
Понятие процесса позволяет говорить о местоположении данных: данные, содержащихся в локальной памяти процесса - расположены ``близко ", другие данные ``удалены". Понятие канала обеспечивает механизм для указания того, что для того, чтобы продолжить вычисление одному процессу требуются данные другого процесса (зависимость по данным).
1.2.2. Модель обмен сообщениями
На сегодняшний день модель обмен сообщениями (message passing) является наиболее широко используемой моделью параллельного программирования. Программы этой модели, подобно программам модели процесс/канал, создают множество процессов, с каждым из которых ассоциированы локальные данные. Каждый процесс идентифицируется уникальным именем. Процессы взаимодействуют, посылая и получая сообщения. В этом отношение модель обмен сообщениями является разновидностью модели процесс/канал и отличается только механизмом, используемым при передаче данных.
Модель обмен сообщениями не накладывает ограничений ни на динамическое создание процессов, ни на выполнение нескольких процессов одним процессором, ни на использование разных программ для разных процессов. Просто, формальные описания систем обмена сообщениями не рассматривают вопросы, связанные с манипулированием процессами. Однако, при реализации таких систем приходится принимать какое-либо решение в этом отношении.
В таких системах каждый процесс выполняет одну и ту же программу (параметризованную относительно идентификатора либо процесса, либо процессора), но работает с разными данными, поэтому о таких системах говорят, что они реализуют SPMD (single program multiple data - одна программа много данных) модель программирования. SPMD модель приемлема и достаточно удобна для широкого диапазона приложений параллельного программирования, но она затрудняет разработку некоторых типов параллельных алгоритмов.
1.2.3. Модель параллелизм данных
Модель параллелизм данных также является часто используемой моделью параллельного программирования. Название модели происходит оттого, что она эксплуатирует параллелизм, который заключается в применении одной и той же операции к множеству элементов структур данных. Например, "умножить все элементы массива M на значение x", или "снизить цену автомобилей со сроком эксплуатации более 5-ти лет". Программа с параллелизмом данных состоит из последовательностей подобных операций. Поскольку операции над каждым элементом данных можно рассматривать как независимые процессы, то степень детализации таких вычислений очень велика, а понятие "локальности" (распределения по процессам) данных отсутствует. Следовательно, компиляторы языков с параллелизмом данных часто требуют, чтобы программист предоставил информацию относительно того, как данные должны быть распределены между процессорами, другими словами, как программа должны быть разбита на процессы. Компилятор транслирует программу с параллелизмом данных в SPMD программу, генерируя коммуникационный код автоматически.
1.2.4. Модель общая память
В модели программирования с общей памяти, все процессы совместно используют общее адресное пространство, к которому они асинхронно обращаются с запросами на чтение и запись. В таких моделях для управления доступом к общей памяти используются всевозможные механизмы синхронизации типа семафоров и блокировок процессов. Преимущество этой модели с точки зрения программирования состоит в том, что понятие собственности данных (монопольного владения данными) отсутствует, следовательно, не нужно явно задавать обмен данными между производителями и потребителями. Эта модель, с одной стороны, упрощает разработку программы, но, с другой стороны, затрудняет понимание и управление локальностью данных, написание детерминированных программ. В основном эта модель используется при программировании для архитектур с общедоступной памятью.
1.3. Система параллельного программирования Linda
Идея построения системы Linda исключительно проста, а потому красива и очень привлекательна. Параллельная программа есть множество параллельных процессов, и каждый процесс работает согласно обычной последовательной программе. Все процессы имеют доступ к общей памяти, единицей хранения в которой является кортеж. Отсюда происходит и специальное название для общей памяти - пространство кортежей. Каждый кортеж это упорядоченная последовательность значений. Например,
( "Hello", 42, 3.14 ), ( "P", 5, FALSE, 97, 1024, 2), ( "worker", 5 ) .
Первый элемент кортежа всегда является символьной строкой и выступает в роли имени кортежа. Так первый кортеж предыдущего примера состоит из имени ("Hello"), элемента целого типа (42) и вещественного числа (3.14). Во втором кортеже кроме имени "P" есть элемент целого типа (5), элемент логического типа (FALSE) и три целых числа. Последний кортеж состоит из двух элементов: имени ("worker") и целого числа (5). Количество элементов в кортеже может быть любым.
Все процессы работают с пространством кортежей по принципу: поместить кортеж, забрать, скопировать. В отличие от традиционной памяти, процесс может забрать кортеж из пространства кортежей, после чего данный кортеж станет недоступным остальным процессам. В отличие от традиционной памяти, если в пространство кортежей положить два кортежа с одним и тем же именем, то не произойдет привычного для нас "обновления" значения переменной - в пространстве кортежей окажется два кортежа с одним и тем же именем. В отличие от традиционной памяти, изменить кортеж непосредственно в пространстве нельзя. Для изменения значений элементов кортежа, его нужно сначала оттуда изъять, затем процесс, изъявший кортеж, может изменить значения его элементов и вновь добавить измененный кортеж в память. В отличие от других систем программирования, процессы в системе Linda никогда не взаимодействуют друг с другом явно, и все общение всегда идет через пространство кортежей.
Интересно, что с точки зрения системы Linda в любой последовательный язык достаточно добавить лишь четыре новые функции, как он становится средством параллельного программирования! Эти функции и составляют систему Linda: три для операций над кортежами и пространством кортежей и одна функция для порождения параллельных процессов. Для определенности, дальнейшее обсуждение системы и ее функций будем вести с использованием языка С.
Функция OUT помещает кортеж в пространство кортежей. Например,
out ( "GoProcess", 5);
помещает в пространство кортежей кортеж ("GoProcess", 5). Если такой кортеж уже есть в пространстве кортежей, то появится второй, что, в принципе, позволяет иметь сколь угодно много экземпляров одинаковых кортежей. По этой же причине с помощью функции out нельзя изменить кортеж, уже находящийся в пространстве. Для этого кортеж должен быть сначала оттуда изъят, затем изменен и после этого помещен назад. Функция out никогда не блокирует выполнивший ее процесс.
Функция IN ищет подходящий кортеж в пространстве кортежей, присваивает значения его элементов элементам своего параметра-кортежа и удаляет найденный кортеж из пространства кортежей. Например,
in( "P", int i, FALSE );
Этой функции соответствует любой кортеж, который состоит из трех элементов: значением первого элемента является "P", второй элемент может быть любым целым числом, а третий должен иметь значение FALSE. Подходящими кортежами могут быть ( "P", 5, FALSE) или ( "P", 135, FALSE) и т.п., но не ( "P", 7.2, FALSE) или ( "Proc", 5, FALSE). Если параметру функции in соответствуют несколько кортежей, то случайным образом выбирается один из них. После нахождения кортеж удаляется из пространства кортежей, а неопределенным формальным элементам параметра-кортежа, содержащимся в вызове данной функции, присваиваются соответствующие значения. В предыдущем примере переменной i присвоится 5 или 135. Если в пространстве кортежей ни один кортеж не соответствуют функции, то вызвавший ее процесс блокируется до тех пор, пока соответствующий кортеж в пространстве не появится.
Элемент кортежа в функции in считается формальным, если перед ним стоит определитель типа. Если используется переменная без определителя типа, то берется ее значение и элемент рассматривается как фактический параметр. Например, во фрагменте программы
int i = 5;
in( "P", i, FALSE ); функции in, в отличие от предыдущего примера, соответствует только кортеж ("P", 5, FALSE).
Если переменная описана до вызова функции и ее надо использовать как формальный элемент кортежа, можно использовать ключевое слово formal или знак '?'. Например, во фрагменте программы
j = 15;
in( "P", formal i, j );
последнюю строку можно заменить и на оператор in("P", ?i, j). В этом примере функции in будет соответствовать, например, кортеж ("P", 6, 15), но не ("P", 6, 12). Конечно же, формальными могут быть и несколько элементов кортежа одновременно:
in ( "Add_If", int i, bool b);
Если после такого вызова функции в пространстве кортежей будет найден кортеж ("Add_If", 100, TRUE), то переменной i присвоится значение 100, а переменной b - значение TRUE.
Функция READ отличается от функции in лишь тем, что выбранный кортеж не удаляется из пространства кортежей. Все остальное точно так же, как и у функции in. Этой функцией удобно пользоваться в том случае, когда значения переменных менять не нужно, но к ним необходим параллельный доступ из нескольких процессов.
Функция EVAL похожа на функцию out. Разница заключается лишь в том, что дополнительным элементом кортежа у eval является функция пользователя. Для вычисления значения этой функции система Linda порождает параллельный процесс, на основе работы которого она формирует кортеж и помещает его в пространство кортежей. Например,
eval ("hello", funct( z ), TRUE, 3.1415);
При обработке данного вызова система создаст новый процесс для вычисления функции funct( z ). Когда процесс закончится и будет получено значение w = funct( z ), в пространство кортежей будет добавлен кортеж ("hello", w, TRUE, 3.1415). Функция, вызвавшая eval, не ожидает завершения порожденного параллельного процесса и продолжает свою работу дальше. Следует отметить и то, что пользователь не может явно управлять размещением порожденных параллельных процессов на доступных ему процессорных устройствах - это Linda делает самостоятельно.
Параллельная программа в системе Linda считается завершенной, если все порожденные процессы завершились или все они заблокированы функциями in и read.
По сути дела, описание системы закончено, и теперь можно привести несколько небольших примеров. Мы уже говорили о том, что параллельные процессы в системе Linda напрямую друг с другом не общаются, своего уникального номера-идентификатора не имеют и общего числа параллельно работающих процессов-соседей, вообще говоря, не знают. Однако если у пользователя есть в этом необходимость, то такую ситуацию очень просто смоделировать. Программа в самом начале вызывает функцию out:
out( "Next", 1);
Этот кортеж будет играть роль "эстафетной палочки", передаваемой от процесса процессу: каждый порождаемый параллельный процесс первым делом выполнит следующую последовательность:
in( "Next", formal My_Id);
out( "Next", My_Id+1);
Первый оператор изымает данный кортеж из пространства, на его основе процесс получает свой номер My_Id, и затем кортеж с номером для следующего процесса помещается в пространство. Заметим, что использование функции in в данном случае позволяет гарантировать монопольную работу с данным кортежем только одного процесса в каждый момент времени. После такой процедуры каждый процесс получит свой уникальный номер, а число уже порожденных процессов всегда можно определить, например, с помощью такого оператора:
read( "Next", formal Num_Processes);
Теперь рассмотрим возможную схему организации программы для перемножения С=A*B двух квадратных матриц размера N*N. Инициализирующий процесс использует функцию out и помещает в пространство кортежей исходные строки матрицы A и столбцы матрицы B:
out( "A",1, );
out( "A",2, );
.
out( "B",1, );
out( "B",2, );
.
Для порождения Nproc идентичных параллельных процессов можно воспользоваться следующим фрагментом:
for( i = 0; i eval( "ParProc", get_elem_result() );
Входные данные готовы, и нахождение всех N2 элементов Cij результирующей матрицы можно выполнять в любом порядке. Главное - это распределить работу между процессами, для чего процесс, инициирующий вычисления, в пространство помещает следующий кортеж:
out( "NextElementCij", 1);
Второй элемент данного кортежа всегда будет показывать, какой из N2 элементов Cij предстоит вычислить следующим. Базовый вычислительный блок функции get_elem_result() будет содержать следующий фрагмент:
in( "NextElementCij", formal NextElement);
if( NextElement out("NextElementCij ", NextElement + 1);
Nrow = (NextElement - 1) / N + 1;
Ncol = (NextElement - 1) % N + 1;
В результате выполнения данного фрагмента для элемента с номером NextElement процесс определит его местоположение в результирующей матрице: номер строки Nrow и столбца Ncol. Заметим, что если вычисляется последний элемент, то кортеж с именем "NextElementCij" в пространство не возвращается. Когда в конце работы программы процессы обратятся к этому кортежу, они будут заблокированы, что не помешает нормальному завершению программы. И, наконец, для вычисления элемента Cij каждый процесс get_elem_result выполнит следующий фрагмент:
read( "A", Nrow, formal row);
read( "B", Ncol, formal col);
out( "result", Nrow, Ncol, DotProduct(row,col) );
где DotProduct это функция, реализующая скалярное произведение. Таким образом, каждый элемент произведения окажется в отдельном кортеже в пространстве кортежей. Завершающий процесс соберет результат, поместив их в соответствующие элементы матрицы C:
for ( irow = 0; irow for ( icol = 0; icol in( "result", irow + 1, icol + 1, formal C[irow][icol]);
Не имея в системе Linda никаких явных средств для синхронизации процессов, совсем не сложно их смоделировать самому. Предположим, что в некоторой точке нужно выполнить барьерную синхронизацию N процессов. Какой-то один процесс, например, стартовый, заранее помещает в пространство кортеж ("ForBarrier", N). Подходя к точке синхронизации, каждый процесс выполняет следующий фрагмент, который и будет выполнять функции барьера:
in( "ForBarrier", formal Bar);
Bar = Bar - 1;
if( Bar != 0 ) {
out( "ForBarrier", Bar);
read( "Barrier" );
} else
out( "Barrier" );
Если кортеж с именем "ForBarrier" есть в пространстве, то процесс его изымает, в противном случае блокируется до его появления. Анализируя второй элемент данного кортежа, процесс выполняет одно из двух действий. Если есть процессы, которые еще не дошли до данной точки, то он возвращает кортеж в пространство с уменьшенным на единицу вторым элементом и встает на ожидание кортежа "Barrier". В противном случае он сам помещает кортеж "Barrier" в пространство, который для всех является сигналом к продолжению работы.
В целом, сильные и слабые стороны системы Linda понятны. Простота и стройность концепции системы является основным козырем, однако эти же факторы оборачивается большой проблемой на практике. Если вычислительная система обладает распределенной памятью, то общение процессов через пространство кортежей заведомо будет сопровождаться большими накладными расходами.
РАЗДЕЛ 2
РАЗРАБОТКА СПРАВОЧНОЙ СИСТЕМЫ
В этом разделе курсового проекта рассматривается прорисовка графических примитивов и вывод справки по функциям API, использованным для создания этого объекта.
2.1. Вызов справки
Вызов справки не должен вызвать затруднений, в связи с тем, что файл справки уже создан и вызывается при нажатии правой кнопки мыши. Для вызова справки используется следующие операторы:
GetCurrentDirectory(256,buf);
strcat(buf,"/help/Shapes.hlp");
WinHelp(hDlg,buf,HELP_CONTENTS,0);
Рассмотрим более подробно синтаксис и назначение функций.
Функция GetCurrentDirectory(nBufferLength: DWORD; lpBuffer: PChar): DWORD возвращает текущий каталог. Обычно это каталог в котором была запущена программа.
Параметры:
nBufferLength - размер буфера для принимаемой строки
lpBuffer - принимый путь
Возвращаемое значение:
В случае успеха строка, содержащая путь, в случае неуспеха 0. Получить дополнительную информацию об ошибке исполнения можно с помощью функции GetLastError. Функция находится в файле kernel32.dll
Функция strcat(buf,"/help/Shapes.hlp") копирует строку "/help/Shapes.hlp" в переменную типа char c именем buf.
Функция WindHelp(Wnd: HWnd; HelpFile: PChar; Command: Word; Data: Longint) вызывает механизм Windows получения спpавочной инфоpмации с командой Command.
Паpаметpы:
Wnd: Идентификатор окна.
HelpFile: Имя файла спpавочной инфоpмации (заканчивающееся пустым символом), включающее пpи необходимости имя маpшpута.
Command: Одна из команд help_Context, help_HelpOnHelp, help_Index, help_Key, help_Quit или help_SetIndex.
Data: Номеp идентификатора контекста, если Command имеет значение help_Context, или ключевое слово спpавочной темы (заканчивающееся пустым символом), если Command имеет значение help_Key.
Возвращаемое значение:
Не нуль в случае успешного завершения; 0 - в противном случае.
2.1. Рисование графических примитивов
При рисовании линий активно используют значение текущей позиции пера. Чтобы узнать текущую позицию пера, вызывают функцию GetCurrentPositionEx: BOOL GetCurrentPositionEx( HDC hdc, LPPOINT IpPoint);
Параметр IpPoint указывает на структуру типа POINT, в которую будут записаны логические координаты текущей позиции. В случае успешного выполнения функция возвращает ненулевое значение.
Чтобы нарисовать прямую линию, вызывают функцию LineTo:
BOOL LineTo( HDC hdc, int x, int у);
В случае успешного выполнения функция LineTo рисует прямую линию из текущей позиции до (но, не включая ее) точки с координатами (х, у). При этом текущая позиция переносится в точку (х, у), а возвращаемое значение отлично от нуля. Для рисования прямой используются текущие установки пера и, если прерывистая линия, текущие установки кисти фона вывода.
При рисовании прямых линий часто приходится сначала перемещать текущую позицию в начало рисуемой прямой и, только затем, вызывать функцию LineTo. Во избежание такой "сложности" описывают функцию следующего вида:
BOOL DrawLine( HDC hdc, int xO, int yO, int x, int y)
{
POINT pt;
MoveToEx (hdc, xO, yO, &pt);
return LineTo (hdc, x, y);
}
Эта функция рисует прямую, начиная от точки (хО, уО), до точки (х, у) и переносит текущую позицию в точку (х, у).
Для рисования эллипса используют функцию Ellipse:
BOOL Ellipse( HOC hdc, int I, int t, int r, int b);
Параметры функции Ellipse идентичны первым пяти параметрам функции Arc. В случае успешного выполнения функция возвращает ненулевое значение. Функция игнорирует текущую позицию.
Сегмент эллипса рисуют при помощи функции Chord:
BOOL Chord(HDC hdc, int I, int t, int r, int b, int xO, int yO, int x, int у);
Параметры этой функции аналогичны параметрам функции Arc.
В отличие от функции Arc, функция Chord соединяет хордой точки начала и конца дуги эллипса и закрашивает выделенный таким образом сегмент текущей кистью. В случае успешного выполнения функция возвращает ненулевое значение. Функция игнорирует текущую позицию.
Функция RoundRect рисует прямоугольник с закругленными углами: BOOL RoundRect( HOC hdc, int I, int t, int r, int b, int w, int h);
Первые 5 параметров этой функции совпадают с параметрами функции Rectangle. А параметры w и h задают соответственно ширину и высоту эллипса, дуги которого закругляют углы прямоугольника. В случае успешного выполнения функция возвращает ненулевое значение. Функция игнорирует текущую позицию.
2.3. Интерфейс программы
Для выбора графических примитивов нужно нажать кнопку “Выбор” в главном окне программы. ( рис. 2.1.)
рис.2.1. Главное окно программы
После нажатия кнопки “Выбор” появится диалоговое окно (рис.2.2.) в котором можно выбрать любой графический примитив, из приведенных в списке.
рис.2.2. Диалоговое окно выбора графических примитивов
После того, как выбор будет закончен, надо нажать кнопку “Добавить”. После этого выбранные примитивы будут занесены в левое окно. В этом окне находятся те фигуры, с которыми можно будет работать после закрытия диалогового окна. В диалоговом окне выбора можно увидеть также кнопки “OK”, “Удалить” и “Отчистить”, назначение которых становится понятно по их названию. По закрытии диалогового окна, в главном окне программы, можно выбрать фигуры для прорисовки и нажать кнопку “Нарисовать”. Выбранные фигуры появятся в правой части экрана. Щелчок правой кнопки по рисунку выводит справку-описание в формате WINHELP по функциям API, использованным для создания выбранного объекта.
2.4. Требования к ПК
Задача реализуется на ПК с установленной операционной системой Windows 98, Windows Me, Windows 2000, Windows XP, Windows 2003. Для эксплуатации программного обеспечения необходимо использовать ПК класса Intel или AMD c минимальными характеристиками: тактовая частота микропроцессора 200 MГц, оперативная память - 64 Mб, видеокарта SVGA совместимая, с 4Мб оперативной памяти и 16бит цветопередача.
Рекомендуемые характеристики:
1. тактовая частота микропроцессора 500 MГц
2. оперативная память - 128 Mб
3. видеокарта – 16 Мб оперативной памяти.
4. монитор – 15 ”, 32 бит цветопередача.
5. операционная система – Windows 2k/ XP/ .NET.
ВЫВОД
Главным критерием качества распараллеливания вычислений является сокращение общего времени решения задачи. На основе параллельных вычислений разработано параллельное программирование, но оно представляет дополнительные источники сложности - необходимо явно управлять работой тысяч процессоров, координировать миллионы межпроцессорных взаимодействий. Решение этих вопросов было рассмотрено в теоретической части курсового проекта.
Во второй (практической) части курсового проекта, была рассмотрена программа для рисования графических примитивов и вызова справки по функциям WinAPI. Данная программа может быть использована в обучающих целях, при рассмотрении задач рисования графических примитивов.
В программе были решены такие задачи:
1. Выбор графических фигур,
2. прорисовки выбранных фигур на экране,
3. вызов справки.
СПИСОК ИСПОЛЬЗУЕМЫХ ИСТОЧНИКОВ
1. Саймон Р. Windows 2000 API. Энциклопедия программиста. – К.: ООО "ДиасофтЮП", 2002. – 1085 с.
2. http://parallel.ru/vvv/lec7.html
3. http://www.ccas.ru/paral/prog/comm_msg/intro.html
5. http://osp.admin.tomsk.ru/os/index.htm
6. http://www.csa.ru/~il/pvm_tutor/
7. MSDN
ПРИЛОЖЕНИЕ А
ЛИСТИНГ ПРОГРАММЫ
//Файл Shapes.cpp
#define STRICT
#include
#pragma hdrstop
#include
#include
#include "shapes.h"
char szAppName[10]; // name of application
HINSTANCE hInst; // hInstance of application
HWND hWndMain; // hWnd of main window
HWND hQryDlgBox; // handle of modeless dialog box
HWND hDlgSelect;
HGLOBAL hdlgr; // handle of dialog resource
FARPROC lpModelessProc; // pointer to proc for modeless box
HDC hdc;
PAINTSTRUCT ps;
HMENU hMenu, hMenuFile, hMenuAvt;
bool flag = false;
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpszCmdLine, int cmdShow);
void InitMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpszCmdLine, int cmdShow);
LRESULT CALLBACK MainWndProc(HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam);
void InitMainDlg(HWND hWnd);
BOOL CALLBACK MainDlgBoxProc(HWND hDlg, UINT message,
WPARAM wParam, LPARAM lParam);
LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK Select(HWND, UINT, WPARAM, LPARAM); // диалог выбора фигур
void fillb(HWND hDlg, int ID);
void PaintShapes(HWND hDlg);
//---------------------------------------------------------------------
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpszCmdLine, int cmdShow)
{
MSG msg;
// Go init this application.
InitMain(hInstance, hPrevInstance, lpszCmdLine, cmdShow);
// Get and dispatch messages for this applicaton.
while (GetMessage(&msg, NULL, 0, 0))
{
if(!hQryDlgBox || !IsWindow(hQryDlgBox) ||
!IsDialogMessage( hQryDlgBox, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return(msg.wParam);
}
void InitMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpszCmdLine, int cmdShow)
{
WNDCLASS wcMainClass;
// Get string from resource with application name.
LoadString(hInstance, IDS_NAME, (LPSTR)szAppName, 10);
// Define the window class for this application.
wcMainClass.lpszClassName = szAppName;
wcMainClass.hInstance = hInstance;
wcMainClass.lpfnWndProc = MainWndProc;
wcMainClass.hCursor = LoadCursor(NULL, IDC_ARROW);
wcMainClass.hIcon = LoadIcon(hInstance, szAppName);
wcMainClass.lpszMenuName = (LPSTR) NULL;
wcMainClass.hbrBackground = (HBRUSH)(COLOR_APPWORKSPACE);//GetStockObject(WHITE_BRUSH);
wcMainClass.style = CS_HREDRAW | CS_VREDRAW;
wcMainClass.cbClsExtra = 0;
wcMainClass.cbWndExtra = 0;
// Register the class
RegisterClass(&wcMainClass);
hInst = hInstance; // save for use by window procs
// Create applications main window.
hWndMain = CreateWindow(
szAppName,
szAppName,
WS_BORDER |
WS_CAPTION |
WS_SYSMENU |
WS_MINIMIZEBOX,
10,
19,
256,
123,
NULL,
NULL,
hInstance,
NULL
);
// Create a thunk for the main dialog box proc function.
lpModelessProc = MakeProcInstance((FARPROC)MainDlgBoxProc, hInst);
InitMainDlg(hWndMain);
}
//*******************************************************************
// MainWndProc - handles messages for this application
//
// paramaters:
// hWnd - The window handle for this message
// message - The message number
// wParam - The WPARAM parmater for this message
// lParam - The LPARAM parmater for this message
//
// returns:
// depends on message.
//
//*******************************************************************
LRESULT CALLBACK MainWndProc(HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_MOVE:
// Move the dialog box on top of our main window every
// time the main window moves.
if (IsWindow(hQryDlgBox))
SendMessage(hQryDlgBox, message, wParam, lParam);
break;
case WM_SETFOCUS:
// Always set the input focus to the dialog box.
if (IsWindow(hQryDlgBox))
SendMessage(hQryDlgBox, message, wParam, lParam);
break;
case WM_CLOSE:
// Tell windows to destroy our window.
DestroyWindow(hWnd);
break;
case WM_QUERYENDSESSION:
// If we return TRUE we are saying it's ok with us to end the
// windows session.
return((long) TRUE); // we agree to end session.
case WM_ENDSESSION:
// If wParam is not zero, it meany every application said ok
// to WM_QUERYENDSESSION messages, so we are really ending.
// if all apps aggreed to end session.
// This is the end. We will not get a
// WM_DESTROY message on end session.
break;
case WM_DESTROY:
// This is the end if we were closed by a DestroyWindow call.
PostQuitMessage(0);
break;
default:
return(DefWindowProc(hWnd, message, wParam, lParam));
}
return(0L);
}
//*******************************************************************
// InitMainDlg - put up modeless dialog box
//
// paramaters:
// hWnd - The window handle of the caller
//
//*******************************************************************
void InitMainDlg(HWND hWnd)
{
// This structure describes the fixed portion at the begining of a
// dialog template. The part we are going to modify is dtItemCount
// to cause the proper number of drive selector boxes to display.
WORD numDrives;
#if !defined( FLAT )
// 16 bit dialog template
typedef struct tagDLGTEMPLATE
{
long dtStyle;
BYTE dtItemCount;
int dtX;
int dtY;
int dtCX;
int dtCY;
char dtResourceName[1];
} DLGTEMPLATE;
typedef LPSTR DLGPTR;
#else
// 32 bit dialog template
typedef struct tagDLGTEMPLATE
{
DWORD dtStyle;
DWORD dtExtStyle;
WORD dtItemCount;
SHORT dtX;
SHORT dtY;
SHORT dtCX;
SHORT dtCY;
} DLGTEMPLATE;
typedef LPCDLGTEMPLATEA DLGPTR;
#endif
DLGTEMPLATE FAR *dltp, *tempDlgPtr;
LPCSTR resourceStr;
HRSRC resourceHndl;
// Modifying dialog box parms on the fly.
// Load the dialog box resource.
resourceStr = MAKEINTRESOURCE(IDD_MAIN);
// CreateDialogIndirect(hInst,resourceStr,hWnd,(DLGPROC)lpModelessProc);
resourceHndl = FindResource(hInst, resourceStr, RT_DIALOG);
hdlgr = LoadResource(hInst, resourceHndl);
if (hdlgr)
{
// Lock the resource so we have a pointer to it.
dltp = (DLGTEMPLATE FAR *) LockResource(hdlgr);
if (dltp)
{
// Change the number of items to display. The drive boxes are
// defined last so we can truncate the ones not needed.
// make a temporary copy of dialog template
tempDlgPtr = (DLGTEMPLATE*) malloc((size_t)SizeofResource(hInst, resourceHndl));
#if defined( FLAT )
memcpy((void *)tempDlgPtr, (const void *)dltp, (size_t)SizeofResource(hInst, resourceHndl));
#else
_fmemcpy((void FAR *)tempDlgPtr, (const void FAR *)dltp, (size_t)SizeofResource(hInst, resourceHndl));
#endif
CreateDialogIndirect(hInst,
(DLGPTR)tempDlgPtr,
hWnd,
(DLGPROC)lpModelessProc);
// free tempory copy of dialog template
free(tempDlgPtr);
// Unlock dialog resource we locked above.
#if !defined( FLAT )
UnlockResource(hdlgr);
#endif
// Free it.
FreeResource(hdlgr);
// Zero handle to it.
hdlgr = 0;
}
}
}
//*******************************************************************
// MainDlgBoxProc - handle Main dialog messages (modeless)
//
// This is a modeless dialog box procedure that controls this
// entire application.
//
// paramaters:
// hDlg - The window handle for this message
// message - The message number
// wParam - The WPARAM parameter for this message
// lParam - The LPARAM parameter for this message
//
//*******************************************************************
#pragma argsused
BOOL CALLBACK MainDlgBoxProc(HWND hDlg, UINT message,
WPARAM wParam, LPARAM lParam)
{
// static HWND hlistwnd;
static RECT wrect;
int index[27];
char buf[256];
int x, y, w, h, i;
switch (message)
{
case WM_INITDIALOG:
// Save the handle of this proc for use by main window proc.
hQryDlgBox = hDlg;
// Get position of dialog box window.
GetWindowRect(hDlg, (LPRECT) &wrect);
w = wrect.right - wrect.left;
h = wrect.bottom - wrect.top;
// Move main application window to same position.
SetWindowPos(hWndMain, hDlg,
wrect.left, wrect.top, w, h,
0);
hMenuAvt=CreatePopupMenu();
AppendMenu(hMenuAvt,MF_ENABLED|MF_STRING,IDM_ABOUT, "&About");
hMenuFile=CreatePopupMenu();
AppendMenu(hMenuFile,MF_ENABLED|MF_STRING,IDM_EXIT, "&Выход");
hMenu = CreateMenu();
AppendMenu(hMenu, MF_ENABLED|MF_POPUP, (UINT) hMenuFile, "&Файл");
AppendMenu(hMenu, MF_ENABLED|MF_POPUP, (UINT) hMenuAvt, "&О программе");
SetMenu(hDlg, hMenu);
break;
case WM_MOVE:
// Always keep this dialog box on top of main window.
GetWindowRect(hWndMain, (LPRECT) &wrect);
x = wrect.left;
y = wrect.top;
w = wrect.right - wrect.left;
h = wrect.bottom - wrect.top;
MoveWindow(hDlg, x, y, w, h, 1);
break;
case WM_SYSCOMMAND:
// Pass WM_SYSCOMMAND messages on to main window so both
// main window and dialog box get iconized, minimized etc.
// in parallel.
SendMessage(hWndMain, message, wParam, lParam);
break;
case WM_RBUTTONUP:
if(flag)
if(LOWORD(lParam)>290 && LOWORD(lParam) 90 && HIWORD(lParam) GetCurrentDirectory(256,buf);
strcat(buf,"/help/Shapes.hlp");
WinHelp(hDlg,buf,HELP_CONTENTS,0);
};
break;
case WM_COMMAND:
switch (GET_WM_COMMAND_ID(wParam, lParam))
{
case IDC_OK3:
ShowWindow(hDlg,SW_HIDE);
ShowWindow(hDlg,SW_SHOW);
break;
case IDM_EXIT:
PostMessage(hWndMain, WM_CLOSE, 0, 0L);
// Destroy ourseleves.
DestroyWindow(hDlg);
break;
case IDM_ABOUT:
DialogBox(hInst, (LPCTSTR)IDD_ABOUT, hDlg, (DLGPROC)About);
break;
case IDC_SELECT:
DialogBox(hInst, (LPCTSTR)IDD_SELECT, hDlg, (DLGPROC)Select);
break;
default:
break;
}
break;
case WM_PAINT:
hdc = BeginPaint(hDlg, &ps);
// TODO: Add any drawing code here .
RECT rt;
GetClientRect(hDlg, &rt);
//---------------------------------------
PaintShapes(hDlg);
//--------------------------------
EndPaint(hDlg, &ps);
break;
case WM_CLOSE:
// Unlock dialog resource we locked above.
#if !defined( FLAT )
UnlockResource(hdlgr);
#endif
// Free it.
FreeResource(hdlgr);
// Zero handle to it.
hdlgr = 0;
// Zero handle to this dialog window.
hQryDlgBox = 0;
// Tell main window to close.
PostMessage(hWndMain, WM_CLOSE, 0, 0L);
// Destroy ourseleves.
DestroyWindow(hDlg);
break;
default:
return FALSE;
}
return(TRUE);
}
// Mesage handler for about box.
LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDC_OK1)
{
EndDialog(hDlg, LOWORD(wParam));
return TRUE;
}
break;
}
return FALSE;
}
// заполнение ListBox списком фигур
void fillb(HWND hDlg, int ID)
{
SendDlgItemMessage(hDlg,ID,LB_ADDSTRING,0,(LPARAM) (LPCTSTR)"горизонтальная линия");
SendDlgItemMessage(hDlg,ID,LB_ADDSTRING,0,(LPARAM) (LPCTSTR)"квадрат");
SendDlgItemMessage(hDlg,ID,LB_ADDSTRING,0,(LPARAM) (LPCTSTR)"шестиугольник");
SendDlgItemMessage(hDlg,ID,LB_ADDSTRING,0,(LPARAM) (LPCTSTR)"восьмиугольник");
SendDlgItemMessage(hDlg,ID,LB_ADDSTRING,0,(LPARAM) (LPCTSTR)"крест");
SendDlgItemMessage(hDlg,ID,LB_ADDSTRING,0,(LPARAM) (LPCTSTR)"Х");
SendDlgItemMessage(hDlg,ID,LB_ADDSTRING,0,(LPARAM) (LPCTSTR)"вертикальная линия");
SendDlgItemMessage(hDlg,ID,LB_ADDSTRING,0,(LPARAM) (LPCTSTR)"ромб");
SendDlgItemMessage(hDlg,ID,LB_ADDSTRING,0,(LPARAM) (LPCTSTR)"Т");
SendDlgItemMessage(hDlg,ID,LB_ADDSTRING,0,(LPARAM) (LPCTSTR)"_|_");
SendDlgItemMessage(hDlg,ID,LB_ADDSTRING,0,(LPARAM) (LPCTSTR)"Н");
SendDlgItemMessage(hDlg,ID,LB_ADDSTRING,0,(LPARAM) (LPCTSTR)"стрелка вверх");
SendDlgItemMessage(hDlg,ID,LB_ADDSTRING,0,(LPARAM) (LPCTSTR)"стрелка вниз");
SendDlgItemMessage(hDlg,ID,LB_ADDSTRING,0,(LPARAM) (LPCTSTR)"треугольник");
SendDlgItemMessage(hDlg,ID,LB_ADDSTRING,0,(LPARAM) (LPCTSTR)"нижний левый прямоугольный треугольник");
SendDlgItemMessage(hDlg,ID,LB_ADDSTRING,0,(LPARAM) (LPCTSTR)"нижний правый прямоугольный треугольник");
SendDlgItemMessage(hDlg,ID,LB_ADDSTRING,0,(LPARAM) (LPCTSTR)"верхний левый прямоугольный треугольник");
SendDlgItemMessage(hDlg,ID,LB_ADDSTRING,0,(LPARAM) (LPCTSTR)"верхний правый прямоугольный треугольник");
SendDlgItemMessage(hDlg,ID,LB_ADDSTRING,0,(LPARAM) (LPCTSTR)"квадрат с диагональю верх лево - низ право");
SendDlgItemMessage(hDlg,ID,LB_ADDSTRING,0,(LPARAM) (LPCTSTR)"квадрат с диагональю низ лево - верх право");
SendDlgItemMessage(hDlg,ID,LB_ADDSTRING,0,(LPARAM) (LPCTSTR)"квадрат с крестом");
SendDlgItemMessage(hDlg,ID,LB_ADDSTRING,0,(LPARAM) (LPCTSTR)"левый треугольник");
SendDlgItemMessage(hDlg,ID,LB_ADDSTRING,0,(LPARAM) (LPCTSTR)"правый треугольник");
SendDlgItemMessage(hDlg,ID,LB_ADDSTRING,0,(LPARAM) (LPCTSTR)"стрелка влево");
SendDlgItemMessage(hDlg,ID,LB_ADDSTRING,0,(LPARAM) (LPCTSTR)"стрелка вправо");
SendDlgItemMessage(hDlg,ID,LB_ADDSTRING,0,(LPARAM) (LPCTSTR)"круг");
SendDlgItemMessage(hDlg,ID,LB_ADDSTRING,0,(LPARAM) (LPCTSTR)"прямоугольник без углов");
}
LRESULT CALLBACK Select(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
int i;
int index[27];
char buf[256];
switch (message)
{
case WM_INITDIALOG:
hDlgSelect = hDlg;
// SendDlgItemMessage(hDlg, IDC_LISTBOX2, LB_RESETCONTENT, 0, 0);
fillb(hDlg,IDC_LISTBOX2);
return TRUE;
case WM_CLOSE:
EndDialog(hDlg, LOWORD(wParam));
return TRUE;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_OK2:
for(i=0;i SendDlgItemMessage(hDlg, IDC_LISTBOX3, LB_SETSEL, (WPARAM) TRUE, (LPARAM) (UINT) -1);
SendDlgItemMessage(hDlg, IDC_LISTBOX3, LB_GETSELITEMS, (WPARAM) 27, (LPARAM) (LPINT) index);
SendDlgItemMessage(hQryDlgBox, IDC_LISTBOX1, LB_RESETCONTENT, 0, 0);
for(i=0;i SendDlgItemMessage(hDlg, IDC_LISTBOX3, LB_GETTEXT, (WPARAM) index[i], (LPARAM) (LPCTSTR) buf);
SendDlgItemMessage(hQryDlgBox, IDC_LISTBOX1, LB_ADDSTRING, 0,(LPARAM) (LPCTSTR) buf);
};
EndDialog(hDlg, LOWORD(wParam));
return TRUE;
case IDC_CLEAR:
SendDlgItemMessage(hDlg, IDC_LISTBOX3, LB_RESETCONTENT, 0, 0);
SendDlgItemMessage(hQryDlgBox, IDC_LISTBOX1, LB_RESETCONTENT, 0, 0);
return TRUE;
case IDC_ADD:
for(i=0;i SendDlgItemMessage(hDlg, IDC_LISTBOX2, LB_GETSELITEMS, (WPARAM) 27, (LPARAM) (LPINT) index);
for(i=0;i SendDlgItemMessage(hDlg, IDC_LISTBOX2, LB_GETTEXT, (WPARAM) index[i], (LPARAM) (LPCTSTR) buf);
SendDlgItemMessage(hDlg, IDC_LISTBOX3, LB_ADDSTRING,0,(LPARAM) (LPCTSTR) buf);
};
SendDlgItemMessage(hDlg, IDC_LISTBOX2, LB_SETSEL, (WPARAM) FALSE, (LPARAM) (UINT) -1);
return TRUE;
case IDC_DELETE:
SendDlgItemMessage(hDlg, IDC_LISTBOX3, LB_GETSELITEMS, (WPARAM) 27, (LPARAM) (LPINT) index);
for(i=0;i SendDlgItemMessage(hDlg, IDC_LISTBOX3, LB_DELETESTRING, (WPARAM) index[i], 0);
};
return TRUE;
}
break;
}
return FALSE;
}
void PaintShapes(HWND hDlg)
{
const int x = 350;
const int y = 150;
int index[27];
char buf[256];
static COLORREF cr=RGB(200,200,200 );//цвет фона
HPEN hPen, hPenOld; //перо
LOGBRUSH lb;
HBRUSH hBrush; //кисть
HBRUSH hOldBrush;
//создание контекста
lb.lbStyle=PS_SOLID;
lb.lbColor=RGB(255,0,0);
//создание пера
hPen=ExtCreatePen(PS_GEOMETRIC | PS_SOLID,1,&lb,0,NULL);
hPenOld=HPEN(SelectObject(hdc,hPen));
//создание кисти
hBrush=CreateSolidBrush(cr);
hOldBrush=HBRUSH(SelectObject(hdc,hBrush));
flag = false;
SendDlgItemMessage(hDlg, IDC_LISTBOX1, LB_GETSELITEMS, (WPARAM) 27, (LPARAM) (LPINT) index);
for(int i=0;i SendDlgItemMessage(hDlg, IDC_LISTBOX1, LB_GETTEXT, (WPARAM) index[i], (LPARAM) (LPCTSTR) buf);
if(strcmp(buf,"горизонтальная линия") == 0){
MoveToEx(hdc, x-50, y, NULL);
LineTo(hdc, x+50, y);
flag = true;
};
if(strcmp(buf,"квадрат") == 0){
MoveToEx(hdc, x-50, y-50, NULL);
LineTo(hdc, x+50, y-50);
LineTo(hdc, x+50, y+50);
LineTo(hdc, x-50, y+50);
LineTo(hdc, x-50, y-50);
flag = true;
};
if(strcmp(buf,"шестиугольник") == 0){
MoveToEx(hdc,x-50,y,NULL);
LineTo(hdc,x-25,y-50);
LineTo(hdc,x+25,y-50);
LineTo(hdc,x+50,y);
LineTo(hdc,x+25,y+50);
LineTo(hdc,x-25,y+50);
LineTo(hdc,x-50,y);
flag = true;
};
if(strcmp(buf,"восьмиугольник") == 0){
MoveToEx(hdc,x-50,y-25,NULL);
LineTo(hdc,x-25,y-50);
LineTo(hdc,x+25,y-50);
LineTo(hdc,x+50,y-25);
LineTo(hdc,x+50,y+25);
LineTo(hdc,x+25,y+50);
LineTo(hdc,x-25,y+50);
LineTo(hdc,x-50,y+25);
LineTo(hdc,x-50,y-25);
flag = true;
};
if(strcmp(buf,"крест") == 0){
MoveToEx(hdc,x,y-50,NULL);
LineTo(hdc,x,y+50);
MoveToEx(hdc,x-50,y,NULL);
LineTo(hdc,x+50,y);
flag = true;
};
if(strcmp(buf,"Х") == 0){
MoveToEx(hdc,x-50,y-50,NULL);
LineTo(hdc,x+50,y+50);
MoveToEx(hdc,x-50,y+50,NULL);
LineTo(hdc,x+50,y-50);
flag = true;
};
if(strcmp(buf,"вертикальная линия") == 0){
MoveToEx(hdc, x, y-50, NULL);
LineTo(hdc, x, y+50);
flag = true;
};
if(strcmp(buf,"ромб") == 0){
MoveToEx(hdc,x-50,y,NULL);
LineTo(hdc,x,y-50);
LineTo(hdc,x+50,y);
LineTo(hdc,x,y+50);
LineTo(hdc,x-50,y);
flag = true;
};
if(strcmp(buf,"Т") == 0){
MoveToEx(hdc,x-50,y-50,NULL);
LineTo(hdc,x+50,y-50);
MoveToEx(hdc,x,y-50,NULL);
LineTo(hdc,x,y+50);
flag = true;
};
if(strcmp(buf,"_|_") == 0){
MoveToEx(hdc,x-50,y+50,NULL);
LineTo(hdc,x+50,y+50);
MoveToEx(hdc,x,y-50,NULL);
LineTo(hdc,x,y+50);
flag = true;
};
if(strcmp(buf,"Н") == 0){
MoveToEx(hdc,x-50,y-50,NULL);
LineTo(hdc,x-50,y+50);
MoveToEx(hdc,x-50,y,NULL);
LineTo(hdc,x+50,y);
MoveToEx(hdc,x+50,y-50,NULL);
LineTo(hdc,x+50,y+50);
flag = true;
};
if(strcmp(buf,"стрелка вверх") == 0){
MoveToEx(hdc,x-50,y,NULL);
LineTo(hdc,x,y-50);
LineTo(hdc,x+50,y);
MoveToEx(hdc,x,y-50,NULL);
LineTo(hdc,x,y+50);
flag = true;
};
if(strcmp(buf,"стрелка вниз") == 0){
MoveToEx(hdc,x-50,y,NULL);
LineTo(hdc,x,y+50);
LineTo(hdc,x+50,y);
MoveToEx(hdc,x,y-50,NULL);
LineTo(hdc,x,y+50);
flag = true;
};
if(strcmp(buf,"треугольник") == 0){
MoveToEx(hdc,x,y-50,NULL);
LineTo(hdc,x+50,y+50);
LineTo(hdc,x-50,y+50);
LineTo(hdc,x,y-50);
flag = true;
};
if(strcmp(buf,"нижний левый прямоугольный треугольник") == 0){
MoveToEx(hdc,x-50,y-50,NULL);
LineTo(hdc,x-50,y+50);
LineTo(hdc,x,y+50);
LineTo(hdc,x-50,y-50);
flag = true;
};
if(strcmp(buf,"нижний правый прямоугольный треугольник") == 0){
MoveToEx(hdc,x+50,y-50,NULL);
LineTo(hdc,x+50,y+50);
LineTo(hdc,x,y+50);
LineTo(hdc,x+50,y-50);
flag = true;
};
if(strcmp(buf,"верхний левый прямоугольный треугольник") == 0){
MoveToEx(hdc,x-50,y-50,NULL);
LineTo(hdc,x,y-50);
LineTo(hdc,x-50,y+50);
LineTo(hdc,x-50,y-50);
flag = true;
};
if(strcmp(buf,"верхний правый прямоугольный треугольник") == 0){
MoveToEx(hdc,x,y-50,NULL);
LineTo(hdc,x+50,y-50);
LineTo(hdc,x+50,y+50);
LineTo(hdc,x,y-50);
flag = true;
};
if(strcmp(buf,"квадрат с диагональю верх лево - низ право") == 0){
MoveToEx(hdc, x-50, y-50, NULL);
LineTo(hdc, x+50, y-50);
LineTo(hdc, x+50, y+50);
LineTo(hdc, x-50, y+50);
LineTo(hdc, x-50, y-50);
LineTo(hdc, x+50, y+50);
flag = true;
};
if(strcmp(buf,"квадрат с диагональю низ лево - верх право") == 0){
MoveToEx(hdc, x-50, y-50, NULL);
LineTo(hdc, x+50, y-50);
LineTo(hdc, x+50, y+50);
LineTo(hdc, x-50, y+50);
LineTo(hdc, x-50, y-50);
MoveToEx(hdc,x-50,y+50,NULL);
LineTo(hdc,x+50,y-50);
flag = true;
};
if(strcmp(buf,"квадрат с крестом") == 0){
MoveToEx(hdc, x-50, y-50, NULL);
LineTo(hdc, x+50, y-50);
LineTo(hdc, x+50, y+50);
LineTo(hdc, x-50, y+50);
LineTo(hdc, x-50, y-50);
LineTo(hdc, x+50, y+50);
MoveToEx(hdc,x-50,y+50,NULL);
LineTo(hdc,x+50,y-50);
flag = true;
};
if(strcmp(buf,"левый треугольник") == 0){
MoveToEx(hdc,x-50,y,NULL);
LineTo(hdc,x+50,y-50);
LineTo(hdc,x+50,y+50);
LineTo(hdc,x-50,y);
flag = true;
};
if(strcmp(buf,"правый треугольник") == 0){
MoveToEx(hdc,x+50,y,NULL);
LineTo(hdc,x-50,y-50);
LineTo(hdc,x-50,y+50);
LineTo(hdc,x+50,y);
flag = true;
};
if(strcmp(buf,"стрелка влево") == 0){
MoveToEx(hdc,x,y-50,NULL);
LineTo(hdc,x-50,y);
LineTo(hdc,x,y+50);
MoveToEx(hdc,x-50,y,NULL);
LineTo(hdc,x+50,y);
flag = true;
};
if(strcmp(buf,"стрелка вправо") == 0){
MoveToEx(hdc,x,y-50,NULL);
LineTo(hdc,x+50,y);
LineTo(hdc,x,y+50);
MoveToEx(hdc,x-50,y,NULL);
LineTo(hdc,x+50,y);
flag = true;
};
if(strcmp(buf,"круг") == 0){
Ellipse(hdc,x-50,y-50,x+50,y+50);
flag = true;
};
if(strcmp(buf,"прямоугольник без углов") == 0){
RoundRect(hdc,x-50,y-30,x+50,y+30,50,50);
flag = true;
};
};
SelectObject(hdc,hOldBrush);
DeleteObject(hBrush);
SelectObject(hdc,hPenOld);
DeleteObject(hPen);
}
//Файл Shapes.h
#define IDD_SELECT 3
#define IDD_ABOUT 2
#define IDC_OK1 104
#define IDC_STATICTEXT1 102
#define IDM_ABOUT 103
#define IDM_EXIT 102
#define IDS_NAME 101
#define IDD_MAIN 1
#define IDC_SELECT 105
#define IDC_LISTBOX1 101
#define IDC_BUTTON1 102
#define IDC_OK3 112
#define IDC_ADD 107
#define IDC_DELETE 108
#define IDC_LISTBOX2 106
#define IDC_CLEAR 111
#define IDC_OK2 110
#define IDC_LISTBOX3 109
/****************************************************************************
shapes.rc
produced by Borland Resource Workshop
*****************************************************************************/
#include "shapes.h"
IDD_MAIN DIALOG 0, 0, 343, 210
EXSTYLE WS_EX_APPWINDOW
STYLE DS_3DLOOK | WS_OVERLAPPED | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX
CAPTION "Shapes"
FONT 8, "MS Sans Serif"
{
CONTROL "Выбор", IDC_SELECT, "button", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 8, 8, 108, 14
CONTROL "ListBox1", IDC_LISTBOX1, "listbox", LBS_MULTIPLESEL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | WS_TABSTOP, 8, 48, 108, 149
CONTROL "Нарисовать", IDC_OK3, "button", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 8, 28, 108, 13
}
STRINGTABLE
{
IDS_NAME, "Shapes"
}
IDD_ABOUT DIALOG 0, 0, 240, 50
STYLE DS_3DLOOK | DS_CONTEXTHELP | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX
CAPTION ""
FONT 8, "MS Sans Serif"
{
CONTROL "OK", IDC_OK1, "button", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 164, 17, 56, 13
CONTROL "Здесь должна быть информация о приложении", IDC_STATICTEXT1, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 12, 13, 120, 22
}
IDD_SELECT DIALOG 0, 0, 389, 182
STYLE DS_MODALFRAME | DS_3DLOOK | DS_CONTEXTHELP | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "Выбор фигур"
FONT 8, "MS Sans Serif"
{
CONTROL "OK", IDC_OK2, "BUTTON", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 168, 16, 52, 14
CONTROL "ListBox1", IDC_LISTBOX3, "listbox", LBS_NOTIFY | LBS_MULTIPLESEL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP, 4, 13, 156, 168
CONTROL "Добавить", IDC_ADD, "button", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 168, 39, 52, 14
CONTROL "Удалить", IDC_DELETE, "button", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 168, 60, 52, 13
CONTROL "ListBox2", IDC_LISTBOX2, "listbox", LBS_NOTIFY | LBS_MULTIPLESEL | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | WS_HSCROLL | WS_TABSTOP, 228, 13, 156, 168
CONTROL "}
ПРИЛОЖЕНИЕ Б
БЛОК – СХЕМА АЛГОРИТМА
Файл Shapes.rc
Shapes.cpp
Загрузка кнопок Выбор
Нарисовать
Выбор кнопки
Продолжение прил. Б
Открыть файл справки
Не открывать файл