Сдам Сам

ПОЛЕЗНОЕ


КАТЕГОРИИ







Казанский национальный исследовательский университет





Казанский национальный исследовательский университет

имени. А.Н. Туполева

----------------------------------------------------------------------------------

Кафедра АСОИУ

 

 

В.И. Медведев

 

Методические указания к заданиям по дисциплине

 

«Технология программирования»

 

Казань 2012

 

 

ВВЕДЕНИЕ К ЗАДАНИЯМ

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

“Объектно-ориентированное программирование” и “Технология программирования”

 

Напомним об основных понятиях объектно-ориентированного программирования и технологии программирования.

 

Объекты, классы и язык UML

 

.NET технология позволяет разрабатывать программу, интегрировав её из компонентов, написанных на разных языках программирования, например, на С++.NET и С#.

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

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



Для графического представления объектно-ориентированных систем в настоящее время используется язык UML.

Унифицированный язык моделирования UML (Unified Modeling Language) предназначен для описания объектно-ориентированных систем в виде совокупности диаграмм, раскрывая статическую и динамическую суть системы как модели, состоящей из взаимодействующих объектов.

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

На рис. 2.1 изображен класс на языке UML. Класс представляется в виде прямоугольника, разделённого на три части, в которых размещается имя класса, перечень атрибутов и, наконец, перечень функций класса. Перед именами данных и функций ставятся символы “– “ и “+”, указывающие на доступ private и public соответственно.

 

Рис. 2.1. Класс CBall

 

Из рис. 2.1 видно, что на языке UML представлен класс, имеющий имя CBall, закрытые данные х и у и открытые функции Set, Move и Show. Важно, что это представление класса не зависит от языков программирования и, в частности, от С++, С++.NET и С#.

 

Рис. 2.2. Объекты класса CBall

 

На рис. 2.2 изображены объекты класса CBall на языке UML. В прямоугольнике помещается имя объекта, отделённое от класса этого объекта двоеточием. Если объект безымянный, то ставится двоеточие перед именем класса. Имя объекта и класса подчёркиваются.

 

Рис. 2.3. Класс MyClass наследует класс BaseClass, содержит объект класса OtherClass и использует класс UsedClass

 

Нотация на рисунке 2.3 показывает наследование одного класса из другого класса, обладание классом объекта другого класса и использование в одном классе другого класса.

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

О многогранности описания разрабатываемой системы на этом языке можно судить по перечню описывающих её диаграмм языка UML: диаграмма взаимодействия (interaction diagram), диаграмма деятельности (activity diagram), диаграмма использования (use case diagram), диаграмма классов (class diagram), диаграмма компонентов (component diagram), диаграмма кооперации (collaboration diagram), диаграмма объектов (object diagram), диаграмма последовательности (sequence diagram), диаграмма развёртывания (deployment diagram), диаграмма состояний (statechart diagram).

В задачи книги не входит подробное изложение языка UML. Познакомиться с нотацией этого языка можно по книге Рамбо Дж., Якобсона А. и Буча Г. “UML: специальный справочник”.

Диаграммы класса языка UML должны использоваться при описании поэтапной разработки программ.

.NETКомпонентно-ориентированное программирование

.NET компонент – это управляемый или ref класс .NET платформы.

Интерфейс IComponent является базовым интерфейсом для всех компонентов, определяя их единообразное поведение.

Класс Component – базовый класс для всех компонентов в среде CLR (Common Language Runtime). Наследуемый этим классом класс MarshalByRefObject позволяет также использовать объект компонента как удалённый, то есть вызывать интерфейсные функции объекта компонента, размещённого в одном приложении, посредством объекта-посредника (proxy - прокси), размещённого в другом приложении того же самого или другого компьютера.

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

Интерфейс IContainer – базовый интерфейс контейнера, содержит свойство Components и две функции: Add() и Remove().

 

Класс Container контейнера наследует интерфейсы IContainer и IDisposable. Он переопределяет свойство Components и виртуальные функции Add(), Remove() и Dispose() интерфейсов IContainer и IDisposable.

 

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

 

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

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

Освобождение управляемых и неуправляемых ресурсов возлагается на сам объект компонента и должно осуществляться перед завершением его работы. Для этого введена специальная функция Dispose().

Шаблон функции Dispose.

///////////////

// C# Шаблон функции Dispose() на C#

. . .

private bool disposed= false;

public event EventHandler Disposed= null;

. . .

public void Dispose ( )

{

Dispose (true);

GC.SupressFinalize (this);

}

 

protected virtual void Dispose (bool disposing )

{

if (! this.disposed) // Если первый вызов функции Dispose, то

{

if (Disposed != null)

Disposed (this, EventArgs.Empty); // Сгенерировать событие Disposed

 

if (disposing)

{

// Здесь освободить управляемые ресурсы

}

 

// Здесь освободить неуправляемые ресурсы

 

}

disposed= true;

}

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

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

 

Класс Monitor одержит статические функции Enter(), TryEnter(), Wait(), Puls(), PulsAll() и Exit().

Объект класса Mutex, используемый для создания объектов, синхронизирующих взаимодействия между потоками и процессами. Класс Mutex включает статическую функцию WaitOne() приостанавливающую выполнение данного потока, пока не освободится ожидаемый этим потоком разделяемый ресурс, и статическую функцию ReleaseMutex() позволяющую потоку открыть используемый этим потоком разделяемый ресурс другому потоку.

 

Сериализация – это представление объекта в виде, необходимом для сохранения его в файле и извлечения его из этого файла, или для передачи объекта по каналу из одного приложения или домена в другое приложение или домен.

 

Удалённый объект располагается в приложении, называемом сервером, а приложение, использующее этот объект, называется клиентом. Процедура “переноса” удалённого объекта из сервера на клиент называется отдалением (remoting).

Располагая интерфейсом удалённого объекта, прокси (transporant proxy и real proxy) на клиенте воспринимает вызовы от клиента удалённому объекту, из которых формируются объекты сообщений, содержащие всю необходимую информацию о вызове, и эти объекты передаются по выстроенной цепочке приёмников (sinks), форматеров (formatters) и каналов (transfer channels) к серверу. Здесь, на сервере, объект-сообщение, снова, пройдя через форматер и приёмники, преобразуется в последнем приёмнике (StackBuilderSink) в нормальный стековый вызов, на который среагирует удалённый объект. Результат выполнения вызова удалённым объектом также преобразуется в объект сообщения, который отправится обратно к ожидающему его прокси на стороне клиента. Итак, вызов из клиента выполнился удалённым объектом на сервере.

Удалённый объект всегда размещается на сервере. Он может быть создан на сервере явно с помощью оператора new и потом постоянно присутствовать на сервере. Либо он может быть активизирован сервером или клиентом при необходимости. В этом случае он создаётся соответственно или сервером или клиентом. Поэтому различают серверную и клиентскую активизацию удалённого объекта.

ЦЕЛИ ЗАДАЧИ ЗАДАНИЙ

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

В результате выполнения заданий студенты должны:

 

1. изучить и применить принципы поэтапной разработки и отладки программ средней сложности.

2. уметь разрабатывать собственные компоненты, создавать из них разнообразные объекты и применять их совместно для реализации требуемых алгоритмов функционирования программы.

3. уметь применять необходимые классы библиотеки NET Framework, создавать из них требуемые объекты, и употреблять их в программе.

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

5. уметь разрабатывать и использовать классы и объекты ресурсов.

6. уметь применять асинхронные вызовы и события.

7. уметь разрабатывать собственный интерфейс программы, применив необходимые интерфейсные элементы на базе классов библиотеки NET Framework.

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

9. уметь создавать и связывать между собой приложения сервера и клиента с помощью прокси и удаленного объекта.

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

 

ОФОРМЛЕНИЕ РЕЗУЛЬТАТОВ

Текстовая часть оформляется в виде пояснительной записки (ПЗ) в соответствии с требованиями стандарта.

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

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

Пояснительная записка должна содержать:

Титульный лист;

Лист оглавления;

1 Задание;

2. Уточнение задания

3. Описание разрабатываемой программной системы с точки зрения пользователя.

4. Описание разрабатываемой программной системы с точки зрения программиста. Данный раздел включает следующие подразделы:

4.1.Объектное и компонентное представление системы.

4.2.События.

4.3.Потоки.

4.3. Ресурсы

5. Поэтапная разработка распреденного приложения.

6. Описание проблем, возникших при разработке программной системы.

7. Список используемой литературы.

8. Приложение. Текст программы.

СОДЕРЖАНИЕ РАЗДЕЛОВ ПОЯСНИТЕЛЬНОЙ ЗАПИСКИ

 

Задание. Текст задания должен соответствовать заданию, выданному преподавателем.

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

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

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

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

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

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

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

Поэтапная разработка программной системы. После предварительного анализа и компонентно-ориентированного представления разрабатываемой программной системы в предыдущем разделе здесь излагается поэтапная её разработка. Разработка каждого этапа даётся отдельным подразделом. Для каждого этапа приводится его тестирующее приложение.

 

Описание проблем, возникших при разработке программной системы. Описываются ошибки, вызвавшие задержку в разработке программы. Особенно уделяется внимание на проблемах, возникших из-за очередной модификации среды разработки Visual Studio .NET фирмой Microsoft, которая неописана.

 

Диаграммы классов разработанной программной системы. Приводятся диаграммы классов разработанной программы

 

ОФОРМЛЕНИЕ РЕЗУЛЬТАТОВ

Пояснительная записка выполняется на листах формата А4( 210*297 мм) или близкого к нему потребительского формата. Текст набирается машинописным способом на одной стороне листа через 1,5 или 2 межстрочных интервалов в формате Times New Roman, размер шрифта 14. Ширина полей: слева 25, справа 10, сверху и снизу 15-20 мм.

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

Рисунки, схемы и другой иллюстративный материал должен иметь подписи.

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

В содержании последовательно перечисляют номера и заголовки всех разделов и подразделов пояснительной записки. Слово «СОДЕРЖАНИЕ» записывают в виде заголовка прописными буквами. При цитировании материалов из литературных источников, патентной и технической документации обязательно должно быть указание на цитируемый источник и авторов. В перечень литературы заносятся только источники, на которые в тексте имеется ссылка.

Приложение помещают в конце пояснительной записки и размещают в нем вспомогательный материал. Каждое приложение должно начинаться с нового листа с указанием в правом верхнем углу листа слова «ПРИЛОЖЕНИЕ» прописными буквами. Приложение может иметь заголовок, который записывается симметрично тексту прописными буквами.

 

СПИСОК ЛИТЕРАТУРЫ

а) основная литература

1. . Медведев В.И. .NET компоненты, контейнеры и удалённые объекты (Серия «Современная прикладная математика и информатика»). – Казань: РИЦ «Школа», 2007. – 320 c.: ил.

2. Медведев В.И. .NET компонентно-ориентированное программирование (Серия “Современная прикладная математика и информатика”). – Казань: РИЦ «Школа», 2012. – 277 c.: ил.(издается)

3.Медведев В.И. Особенности объектно-ориентированного программирования на C++/CLI, C# и Java. 3-е изд., испр. и доп. – Казань: РИЦ «Школа», 2011. – 430 c.: ил

 

б) дополнительная литература:

 

1. Juval Lowy. Programming.NET Components. 2nd Edition. – O’Reilly Media,

2005. – 626 pp.

2. Ingo Rammer, Mario Szpuszta. Advanced .NET Remoting. 2nd Edition. – Apress, 2005. – 579 pp.

4. Рамбо Дж., Якобсон А., Буч Г. UML: специальный справочник. – СПб.: Питер, 2002. – 656 c.

Казань 2012

 

Содержание

 

1. Задание

2. Уточнение задания

3. Описание разрабатываемой программы с точки зрения пользователя.

4. Описание разрабатываемой программы с точки зрения программиста.

Объектное и компонентное представление программы.

События, потоки и ресурсы.

5. Поэтапная разработка программной системы без удаленного объекта.

5.1. Первый этап. Разработка компонента Warehouse

5.2. Второй этап. Разработка компонентов ContrlRegion и Lorry

5.3. Третий этап. Разработка приложения csLorryAndWarehouse

6. Описание проблем, возникших при разработке программной системы.

7. Список используемой литературы.

8. Приложение 1. Диаграмма классов разработанной программы.

9. Приложение 2. Текст программы.

10. Продолжение поэтапной разработки программной системы

с удаленным объектом

10.1.Четвертый этап. Удалённый компонент RemObj

10.2. Пятый этап. Сервер csLorryAndWarhousesServer

10.3. Шестой этап. Клиент csLorryAndWarhousesClient

 

Задание

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

 

2. Уточнение задания

 

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

 

 

События, потоки и ресурсы

 

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

Операции объектов компонента Lorry, связанные со складами и с объектом зоны контроля должны быть синхронизированы.

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

Что же касается захода грузовиков в зону контроля, то время пребывания в этой зоне на обследование и ремонт определяется только грузовиком. Поэтому объект region зоны контроля рассматривается как разделяемый ресурс. Каждый объект компонента Lorry должен захватывать, использовать в течение случайного промежутка времени и освобождать этот ресурс. При удалении объект компонента Lorry обязан освободить разделяемый ресурс, если он его использует, чтобы другие объекты компонента Lorry могли им воспользоваться. Для синхронизации доступа объектов компонента Lorry к разделяемому ресурсу можно воспользоваться семафором (mutex).

 

После такого предварительного анализа задачи можно приступить к поэтапной разработке программы.

 

 

Компонент Warehouse.

///////////////

// C# компонент Warehouse

using System;

using System.Drawing;

using System.Threading;

using System.Windows.Forms;

using System.ComponentModel;

 

namespace csWarehouseDll

{

// Класс данных события evFromWarehouse

public class WarehouseEventArgs: EventArgs

{

private bool left; // Признак идентификации склада

private bool full; // Признак заполненности склада

 

public WarehouseEventArgs (bool left, bool full)

{this.left= left; this.full= full;}

 

// Свойство заполнения склада

public bool Full

{get {return full;}}

 

// Свойство идентификации склада

public bool Left

{get {return left;}}

}

 

// Делегат события о переполнении и опустошении склада

public delegate void DelEvFromWarehouse (object sender,

WarehouseEventArgs args);

 

// Интерфейс склада

public interface IWarehouse

{

void Put ( ); // Поместить груз в склад

void Get ( ); // Получить груз из склада

event DelEvFromWarehouse evFromWarehouse; // Ссылка на объект

// события о переполнении и опустошении склада

}

 

// Компонент склада

public class Warehouse: UserControl, IWarehouse

{

bool left; // Признак идентификации склада

int allLoad= 100; // Текущий размер груза в складе

int PartLoad= 10; // Размер груза грузовика

int partLoad; // Разгружаемая или загружаемая порция груза

int numParts= 5; // Количество порций

int timePeriod= 100; // Время разгрузки или загрузки

// порции груза

Thread thr; // Ссылка на объект потока

 

public event DelEvFromWarehouse evFromWarehouse; // Ссылка

// на объект события о переполнении и опустошении склада

 

// Конструктор

public Warehouse (bool left, bool full)

{

this.left= left;

if (!full) allLoad= 0; // Склад пуст

}

 

// Разгрузить груз в склад

public void Put ( )

{

if (((100 - allLoad) < PartLoad) && (evFromWarehouse != null)) {

// Недостаточно места в складе для разгрузки грузовика

WarehouseEventArgs wH= new WarehouseEventArgs (left,

true);

evFromWarehouse (this, wH); // Сгенерировать событие

return;

}

// Разгрузить грузовик и увеличить порциями груз склада

// с помощью потока

partLoad= PartLoad; // Определить выгрузку

// Создать поток выгрузки склада

thr= new Thread (new ThreadStart (Change));

thr.Start ( ); // Стартовать поток

thr.Join ( ); // Подождать завершения потока

}

 

// Получить груз из склада

public void Get ( )

{

if (((allLoad) < PartLoad) && (evFromWarehouse != null))

{

// Недостаточно груза в складе для загрузки грузовика

WarehouseEventArgs wH= new WarehouseEventArgs

(left, false);

evFromWarehouse (this, wH); // Сгенерировать событие

return;

}

// Загрузить грузовик и уменьшить порциями груз склада

// с помощью потока

partLoad= -PartLoad; // Определить выгрузку

// Создать поток загрузки склада

thr= new Thread (new ThreadStart (Change));

thr.Start ( ); // Стартовать поток

thr.Join ( ); // Подождать завершения потока

}

 

// Разгрузить или загрузить груз порциями

protected void Change ( )

{

// Выполнить операцию только с одним грузовиком

Monitor.Enter (this); // Начать критическую секцию

for (int i= 0; i < numParts; i++)

if ((allLoad >= 0 && partLoad < 0) ||

(allLoad <= 100 && partLoad > 0))

{

allLoad += partLoad/numParts;

Thread.Sleep (timePeriod);

Invalidate ( );

}

Monitor.Exit (this); // Завершить критическую секцию

}

 

// Перерисовать размещение груза в складе

protected override void OnPaint (PaintEventArgs e)

{

base.OnPaint (e);

e.Graphics.FillRectangle (new SolidBrush (Color.Yellow), 0,

100 - allLoad, ClientSize.Width, ClientSize.Height);

e.Graphics.DrawString (allLoad.ToString ( ), Font,

new System.Drawing.SolidBrush (Color.Blue), 5, 10);

}

}

}

 

Приложение csTestWarehouse.

///////////////

// C#

using System;

using System.Drawing;

using System.Threading;

using System.Windows.Forms;

using System.ComponentModel;

using csWarehouseDll;

 

namespace csTestWarehouse

{ class TestWarehouse: Form

{

Warehouse leftWH, rightWH; // Ссылки на объекты

// компонента Warehouse

bool leftRight; // Признак направления перемещения грузовиков

bool life; // Признак жизни потока управления загрузкой

// и выгрузкой складов

Thread thr; // Ссылка на поток управления загрузкой

// и выгрузкой складов

 

public TestWarehouse ( )

{

// Создать объект левого склада

leftWH= new Warehouse (true, true);

leftWH.Location= new Point (10, 10);

leftWH.Size= new Size (30, 100);

leftWH.BackColor= Color.White;

leftWH.evFromWarehouse+=

new DelEvFromWarehouse (WarehouseHandler);

this.Controls.Add (leftWH);

leftWH.Show ( );

 

// Создать объект правого склада

rightWH= new Warehouse (false, false);

rightWH.Location= new Point (100, 10);

rightWH.Size= new Size (30, 100);

rightWH.BackColor= Color.White;

rightWH.evFromWarehouse+=

new DelEvFromWarehouse (WarehouseHandler);

this.Controls.Add (rightWH);

rightWH.Show ( );

 

// Создать и запустить поток управления загрузкой

// и выгрузкой складов

leftRight= true;

life= true;

thr= new Thread(new ThreadStart (Go));

thr.Start ( );

}

 

// Обработать событие evFromWarehouse

void WarehouseHandler (object ob, WarehouseEventArgs arg)

{

// Выдать информацию о направлении перемещения и

// о складе, объект которого сгенерировал событие

Console.Write("event evFromWarehouse leftRight=" +

leftRight);

if (arg.Left)

Console.Write(" Компонент leftWH ");

else

Console.Write(" Компонент rightWH ");

 

if (arg.Full)

Console.WriteLine(" полный");

else

Console.WriteLine(" пустой");

Console.WriteLine( );

 

// Изменить направление перемещения грузовиков

if( (arg.Left && arg.Full)||

(!arg.Left && !arg.Full))

leftRight= true;

 

if ((arg.Left && !arg.Full)||

(!arg.Left && arg.Full))

leftRight= false;

}

 

// Обеспечить загрузку груза в склады и

// выгрузку груза из складов

void Go ( )

{

while (life)

{ if (leftRight) {leftWH.Get ( ); rightWH.Put ( );}

else {leftWH.Put ( ); rightWH.Get ( );}

}

}

 

// Завершить поток управления загрузкой

// и выгрузкой складов

void Finish ( )

{

life= false;

thr.Join ( );

}

 

static void Main ( )

{

// Создать объект прикладного окна

TestWarehouse testWH= new TestWarehouse ( );

// Запустить приложение с прикладным окном

Application.Run (testWH);

// Завершить поток управления загрузкой

// и выгрузкой складов

testWH.Finish ( );

}

}

}

/*

Result:

event evFromWarehouse leftRight= True Компонент leftWH пустой

event evFromWarehouse leftRight= False Компонент rightWH полный

event evFromWarehouse leftRight= False Компонент leftWH полный

event evFromWarehouse leftRight= True Компонент leftWH пустой

. . .

*/

 

 

 

Рис. Результат работы приложения csTestWarehouse.

 

 

Компонент csContrlRegion.

///////////////

// C#

using System;

using System.Threading;

using System.Windows.Forms;

 

namespace csContrlRegionDll

{

// Компонент ContrlRegion

public class ContrlRegion: UserControl

{ Mutex mutex; // Ссылка на объект мютекса

 

// Конструктор

public ContrlRegion ( )

{mutex= new Mutex ( ); }

 

// Свойство Semaphore

public Mutex Semaphore

{get {return mutex;}}

}

}

 

Рис. Диаграмма классов компонента Lorry

 

Компонент csLorry.

///////////////

// C#

using System;

using System.Threading;

using System.Drawing;

using System.ComponentModel;

using System.Windows.Forms;

using csWarehouseDll;

using csContrlRegionDll;

 

namespace csLorryDll

{

// Компонент Lorry

public class Lorry : Component

{ int number; // Номер объекта компонента

Point p; // Координаты объекта компонента

int dX; // Приращение координаты Х

bool leftRight; // Направление перемещения груза

ContrlRegion region; // Ссылка на зону контроля

bool inContrl; // Признак нахождения в зоне контроля

Random rand; // Ссылка на объект случайного числа

bool life; // Признак жизни потока

bool run; // Признак выполнения потока

Thread thr; // Ссылка на объект потока

int timePeriod= 100; // Временной интервал перемещения

Warehouse leftWH; // Ссылка на левый склад

Warehouse rightWH; // Ссылка на правый склад

 

// Конструктор

public Lorry (int Number, int Y, int DX, Warehouse LeftWH,

Warehouse RightWH, ContrlRegion Region)

{

number= Number; dX= DX; leftRight= true; life= false;

run= false; leftWH= LeftWH; rightWH= RightWH;

region= Region; inContrl= false; p= new Point ( );

p.X= leftWH.Location.X+leftWH.Width + 1; p.Y= Y;

rand= new Random ( );

// Создать объект потока

thr= new Thread (new ThreadStart (Moving));

}

 

// Свойство Number

public int Number {get {return number;}}

 

// Свойство Point

public Point Point {get {return p;}}

 

// Свойство LeftRight

public bool LeftRight

{

set {leftRight= value;}

get {return leftRight;}

}

 

// Стартовать поток

public void Start ( )

{

life= true; run= true;

thr.Start ( );

}

 

// Завершить поток

public void Finish ( ) {life= false; thr.Join ( );}

 

// Приостановить поток

public void Stop ( )

{

if (run)

{ run= false;

thr.Suspend ( );

}

}

 

// Возобновить поток

public void Run ( )

{

if (!run)

{ run= true;

thr.Resume ( );

}

}

 

// Потоковая функция компонента

private void Moving ( )

{

while (life)

{ // Объект компонента достиг справа

// объекта левого склада

if (p.X <= leftWH.Location.X+leftWH.Width)

{

Console.WriteLine ("Левая граница");

if (leftRight) // Пересылка слева направо

leftWH.Get ( ); // Загрузить груз

else

leftWH.Put ( ); // Выгрузить груз

dX= -dX;

}

// Объект компонента достиг слева

// объекта правого склада

if (p.X >= rightWH.Location.X)

{

Console.WriteLine ("Правая граница");

if (leftRight) // Пересылка слева направо

rightWH.Put ( ); // Выгрузить груз

else

rightWH.Get ( ); // Загрузить груз

dX= -dX;

}

// Обслужить в зоне контроля

Point pR= new Point (region.Location.X,

region.Location.Y);

Rectangle rect= new Rectangle (pR.X, pR.Y, region.Width,

region.Height);

// Вошли в зону контроля

if (rect.Contains (p) && !inContrl) // Вошли в зону

{

Console.WriteLine ("Вошли в зону");

inContrl= true;

 

// Захватить разделяемый ресурс

region.Semaphore.WaitOne ( );

Thread.Sleep (rand.Next (100, 300));

}

if (!rect.Contains (p) && inContrl) // Вышли из зоны

{

Console.WriteLine ("Вышли из зоны");

inContrl= false;

// Освободить разделяемый ресурс

region.Semaphore.ReleaseMutex ( ); }

Thread.Sleep (timePeriod);

p.X += dX;

}

}

}

}

 

 

Приложение csTestLorry.

///////////////

// C#

using System;

using System.Threading;

using System.Drawing;

using System.ComponentModel;

using System.Windows.Forms;

using csWarehouseDll;

using csContrlRegionDll;

using csLorryDll;

 

namespace csTestLorry

{

class TestLorry: Form

{

Warehouse leftWH; // Ссылки на объект левого склада

Warehouse rightWH; // Ссылки на объект правого склада

Lorry lorry1, lorry2; // Ссылки на объекты грузовиков

ContrlRegion region; // Ссылка на объект зоны контроля

bool leftRight; // Признак направления перемещения грузовиков

bool life; // Признак жизни потока управления загрузкой

// и выгрузкой складов

Thread thr; // Ссылка на поток управления загрузкой

// и выгрузкой складов

 

public TestLorry ( )

{

// Создать объект левого склада

leftWH= new Warehouse (true, true);

leftWH.Location= new Point (10, 10);

leftWH.Size= new Size (30, 100);

leftWH.BackColor= Color.White;

leftWH.evFromWarehouse+=

new DelEvFromWarehouse (WarehouseHandler);

this.Controls.Add (leftWH);

leftWH.Show ( );

// Создать объект правого склада

rightWH= new Warehouse (false, false);

rightWH.Location= new Point (200, 10);

rightWH.Size= new Size (30, 100);

rightWH.BackColor= Color.White;

rightWH.evFromWarehouse+=

new DelEvFromWarehouse (WarehouseHandler);

this.Controls.Add (rightWH);

rightWH.Show ( );

// Создать область контроля

region= new ContrlRegion ( );

region.Location= new Point (100, 0);

region.Size= new Size (40, ClientSize.Height);

region.BackColor= Color.LightSkyBlue;

this.Controls.Add (region);

region.Show ( );

// Задать начальное движение грузовиков слева направо

leftRight= true;

// Создать первый объект грузовика

lorry1= new Lorry (1, 10, 10, leftWH, rightWH, region);

lorry1.Start ( );

// Создать второй объект грузовика

lorry2= new Lorry (2, 40, 20, leftWH, rightWH, region);

lorry2.Start ( );

// Создать и запустить поток управления загрузкой

// и выгрузкой складов

life= true;

thr= new Thread (new ThreadStart (Go));

thr.Start ( );

}

 

// Обработать событие evFromWarehouse

void WarehouseHandler (object ob, WarehouseEventArgs arg)

{

// Выдать информацию о направлении перемещения грузо-

// виков и о складе, объект которого сгенерировал событие

Console.Write("event evFromWarehouse leftRight=" +

leftRight);

if (arg.Left)

Console.Write (" Компонент leftWH ");

else Console.Write (" Компонент rightWH ");

if (arg.Full)

Console.WriteLine(" полный");

else Console.WriteLine(" пустой");

Console.WriteLine( );

 

// Изменить направление перемещения грузовиков

if( (arg.Left && arg.Full)||

(!arg.Left && !arg.Full))

leftRight= true;

 

if ((arg.Left && !arg.Full)||

(!arg.Left && arg.Full))

leftRight= false;

// Указать направление грузовикам

lorry1.LeftRight= leftRight;

lorry2.LeftRight= leftRight;

}

 

// Обеспечить загрузку груза в склады и

// выгрузку груза из складов

void Go ( )

{

while (life)

{

Invalidate ( );

Thread.Sleep (50);

}

}

 

// Завершить поток управления загрузкой

// и выгрузкой складов

void Finish()

{

life= false;

thr.Join ( );

lorry1.Finish ( );

lorry2.Finish ( );

}

 

// Завершить все потоки при закрытии прикладного окна

protected override void OnClosed (EventArgs e)

{

base.OnClosed (e);

Finish ( );

}

 

// Перерисовать область клиента прикладного окна

protected override void OnPaint (PaintEventArgs e)

{

base.OnPaint (e);

e.Graphics.DrawEllipse (new Pen (Color.Blue, 2),

lorry1.Point.X - 10, lorry1.Point.Y - 10, 20, 20);

e.Graphics.DrawString (lorry1. Number.ToString ( ), Font,

new SolidBrush (Color.Red), lorry1.Point.X - 3,

lorry1.Point.Y- 4);

e.Graphics.DrawEllipse (new Pen (Color.Blue, 2),

lorry2.Point.X - 10, lorry2.Point.Y - 10, 20, 20);

e.Graphics.DrawString (lorry2.Number.ToString ( ), Font,

new SolidBrush (Color.Red), lorry2.Point.X - 3,

lorry2.Point.Y - 4); }

 

static void Main ( )

{

// Создать объект прикладного окна

TestLorry testLorry= new TestLorry ( );

// Запустить приложение с прикладным окном

Application.Run (testLorry);

}

}

}

 

 

Рис. Прикладное и консольное окна програм









Не нашли то, что искали? Воспользуйтесь поиском гугл на сайте:


©2015- 2018 zdamsam.ru Размещенные материалы защищены законодательством РФ.