
Библиотека csContrlRegion.Dll
///////////////
// C# File csContrlRegion Компонент ContrlRegion
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;}
}
}
}
Библиотека csLorry.Dll
///////////////
// C# File csLorry Компонент Lorry
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;
}
}
}
}
Приложение csLorryAndWarehouse
///////////////
// C# File csLorryAndWarehouse Приложение csLorryAndWarehouse
// Приложение с компонентами Lorry, Warehouse и с управляющими
// элементами
//
using System;
using System.ComponentModel;
using System.Collections;
using System.Drawing;
using System.Threading;
using System.Windows.Forms;
using csLorryDll;
using csWarehouseDll;
using csContrlRegionDll;
namespace csLorryAndWarehouse
{
// Интерфейс контейнера грузовиков
interface ILorryContainer
{
void AddLorry ( );
void RemoveLorry (int carrNumber);
void RemoveAllLorriers ( );
ArrayList GetNumLorriers ( );
void RunLorriers ( );
void StopLorriers ( );
}
// Контейнер грузовиков
class LorryContainer: Container, ILorryContainer
{
Warehouse leftWH; // Ссылки на объект левого склада
Warehouse rightWH; // Ссылки на объект правого склада
Lorry lorry; // Ссылки на объект грузовика
ContrlRegion region; // Ссылка на объект зоны контроля
bool leftRight; // Признак направления перемещения грузовиков
int numLorry= 0; // Номер грузовика
int Y; // Координата Y пути грузовика
Random rand; // Ссылка на случайное число
// Конструктор
public LorryContainer (Warehouse leftWH, Warehouse rightWH,
ContrlRegion region)
{
this.leftWH= leftWH; this.rightWH= rightWH;
this.region= region;
Y= 20; rand= new Random ( );
leftRight= true;
leftWH.evFromWarehouse += new DelEvFromWarehouse
(this.EvFromWarehouseHandler);
rightWH.evFromWarehouse += new DelEvFromWarehouse
(this.EvFromWarehouseHandler);
}
// Добавить грузовик
public void AddLorry ( )
{
numLorry++;
Y += 20;
int dX = rand.Next (5, 10);
if (leftRight) dX= dX;
else dX= -dX;
lorry= new Lorry (numLorry, Y, dX, leftWH, rightWH,
region);
this.Add (lorry);
lorry.Start ( );
}
// Удалить грузовик
public void RemoveLorry (int lorryNumber)
{
IEnumerator inum= this.Components.GetEnumerator ( );
while (inum.MoveNext ( ))
{
Lorry comp= (Lorry) inum.Current;
if (comp.Number == lorryNumber)
{
comp.Finish ( );
this.Remove (comp);
return;
}
}
}
// Получить список номеров грузовиков
public ArrayList GetNumLorriers ( )
{
ArrayList arList= new ArrayList ( );
IEnumerator inum= this.Components.GetEnumerator ( );
while (inum.MoveNext ( ))
{
Lorry comp= (Lorry) inum.Current;
arList.Add (comp.Number);
}
return arList;
}
// Возобновить движение грузовиков
public void RunLorriers ( )
{
IEnumerator inum= this.Components.GetEnumerator ( );
while (inum.MoveNext ( ))
{
Lorry comp= (Lorry) inum.Current;
comp.Run ( );
}
}
// Приостановить движение грузовиков
public void StopLorriers ( )
{
IEnumerator inum= this.Components.GetEnumerator ( );
while (inum.MoveNext ( ))
{
Lorry comp= (Lorry) inum.Current;
comp.Stop ( );
}
}
// Удалить все грузовики
public void RemoveAllLorriers ( )
{
IEnumerator inum= this.Components.GetEnumerator ( );
while (inum.MoveNext ( ))
{
Lorry comp= (Lorry) inum.Current;
comp.Finish ( );
this.Remove (comp);
}
}
// Выдать номера грузовиков на консоль
public void ShowComponents ( )
{
IEnumerator inum= this.Components.GetEnumerator ( );
while (inum.MoveNext ( ))
{
Lorry comp= (Lorry) inum.Current;
Console.WriteLine("компонент номер " +
comp.Number.ToString ( ));
}
}
// Обработать событие склада
public void EvFromWarehouseHandler (object sender,
WarehouseEventArgs args)
{
leftRight= !leftRight;
IEnumerator inum= this.Components.GetEnumerator ( );
while (inum.MoveNext ( ))
{
Lorry comp= (Lorry) inum.Current;
comp.LeftRight= leftRight;
}
}
}
//-------------------------
class LorryAndWarhouses: Form
{
Warehouse leftWH; // Ссылки на объект левого склада
Warehouse rightWH; // Ссылки на объект правого склада
ContrlRegion region; // Ссылка на объект зоны контроля
Thread thread; // Ссылка но объект потока перерисовки
bool life; // Признок жизни потока перерисовки
Button butRun, butStop; // Ссылки на интерфейсные кнопки
Button butAdd, butDel; // Ссылки на интерфейсные кнопки
ListBox listBox; // Список номеров грузовиков
LorryContainer lorryCont;// Ссылка на контейнер грузовиков
// Конструктор
LorryAndWarhouses ( )
{
this.Text= "Test";
this.ClientSize= new Size (350, 130);
// Создать кнопки
butRun= new Button ( ); // Создать кнопку пуска
butRun.Location= new Point (240,5);
butRun.Size= new Size (45, 20);
butRun.Text= "Run";
butRun.BackColor= Color.LightGray;
butRun.Click += new EventHandler (But_Run);
this.Controls.Add (butRun);
//-----
butStop= new Button ( ); // Создать кнопку останова
butStop.Location= new Point (290,5);
butStop.Size= new Size (45, 20);
butStop.Text= "Stop";
butStop.BackColor= Color.LightGray;
butStop.Click += new EventHandler (But_Stop);
this.Controls.Add(butStop);
//-----
butAdd= new Button ( ); // Создать кнопку добавления butAdd.Location= new Point (240,30);
butAdd.Size= new Size (65, 20);
butAdd.Text= "Добавить";
butAdd.BackColor= Color.LightGray;
butAdd.Click += new EventHandler (But_Add);
this.Controls.Add(butAdd);
butDel= new Button ( ); // Создать кнопку удаления butDel.Location= new Point (240,60);
butDel.Size= new Size (65, 20);
butDel.Text= "Удалить";
butDel.BackColor= Color.LightGray;
butDel.Click += new EventHandler(But_Del);
this.Controls.Add(butDel);
listBox= new ListBox ( ); // Создать элемент списка
listBox.Location= new Point (240, 90);
listBox.Size= new System.Drawing.Size (60, 20);
this.Controls.Add (listBox);
// Создать склады
// Создать объект левого склада
leftWH= new Warehouse (true, true);
leftWH.Location= new Point (10, 10);
leftWH.Size= new Size (30, 100);
leftWH.BackColor= Color.White;
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;
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 ( );
// Создать контейнер компонентов
lorryCont= new LorryContainer (leftWH, rightWH, region); // Создать поток перерисовки и запустить его
life= true;
thread= new Thread(new ThreadStart (ThrPaint));
thread.Start();
}
// Обработать нажатие кнопки пуска
private void But_Run (object o, EventArgs e)
{
lorryCont.RunLorriers ( );
}
// Обработать нажатие кнопки останова
private void But_Stop (object o, EventArgs e )
{
lorryCont.StopLorriers ( );
}
// Обработать нажатие кнопки добавления грузовика
private void But_Add (object o, EventArgs e)
{
lorryCont.AddLorry ( );
lorryCont.ShowComponents ( );
ArrayList aL= new ArrayList ( );
aL= lorryCont.GetNumLorriers( );
listBox.Items.Clear ( );
for (int i= 0; i < aL.Count; i++)
listBox.Items.Add (aL[i]);
}
// Обработать нажатие кнопки удаления грузовика
private void But_Del (object o, EventArgs e )
{
if (listBox.SelectedIndex == -1)
{
MessageBox.Show
("Выберете номер удаляемого грузовика в"
+ "\nэлементе списка перед нажатием кнопки");
}
else
{
int numSel= (int) listBox.SelectedItem;
listBox.Items.Remove (numSel);
lorryCont.RemoveLorry (numSel);
ArrayList aL= new ArrayList ( );
aL= lorryCont.GetNumLorriers ( );
listBox.Items.Clear ( );
for (int i= 0; i < aL.Count; i++)
listBox.Items.Add (aL[i]);
lorryCont.ShowComponents ( );
}
}
// Потоковая функция перерисовки
private void ThrPaint ( )
{
while (life)
{
Invalidate ( );
Thread.Sleep (150);
}
}
// Завершить поток перерисовки
public void Finish ( )
{
life= false; thread.Join ( );
}
// Обработать кнопку закрытия окна
protected override void OnClosed (EventArgs e)
{
base.OnClosed (e);
lorryCont.RemoveAllLorriers ( );
Finish ( );
}
// Перерисовать область клиента прикладного окна
protected override void OnPaint (PaintEventArgs e)
{
base.OnPaint (e);
IEnumerator inum= lorryCont.Components.GetEnumerator ( );
while (inum.MoveNext ( ))
{
Lorry comp= (Lorry) inum.Current;
e.Graphics.DrawEllipse (new Pen(Color.Blue, 2),
comp.Point.X - 10, comp.Point.Y - 10, 20, 20);
e.Graphics.DrawString (comp.Number.ToString ( ), Font,
new SolidBrush (Color.Blue), comp.Point.X + 10,
comp.Point.Y + 10);
}
}
// Основная функция
static void Main ( )
{
Application.Run (new LorryAndWarhouses ( ));
}
}
}
Приложение 2. Программа LorryAndWarehouse с удалённым объектом на языках C++/CLI и C#
Библиотека ccLorry.dll на языке С++/CLI
///////////////
// C++/CLI компонент Lorry
// Поместить библиотеки csWarehouse.dll и csContrlRegion.dll
// в директорий ccLorry\debug
#pragma once
#using <mscorlib.dll>
#using <System.Dll>
#using <System.Drawing.Dll>
#using <System.Windows.Forms.Dll>
#using <..\csWarehouse\bin\debug\csWarehouse.dll>
#using <..\csContrlRegion\bin\debug\csContrlRegion.dll>
using namespace System;
using namespace System::Threading;
using namespace System::Drawing;
using namespace System::ComponentModel;
using namespace System::Windows::Forms;
using namespace csWarehouseDll;
using namespace csContrlRegionDll;
namespace ccLorryDll
{
public ref class Lorry: public Component
{
int number; // Номер объекта компонента
Point p, pR; // Координаты объекта компонента
Rectangle rect; // Прямоугольник зоны контроля
int dX; // Приращение координаты Х
bool leftRight; // Направление перемещения груза
ContrlRegion ^region;// Ссылка на зону контроля
bool inContrl; // Признак нахождения в зоне контроля
Random ^time; // Ссылка на объект случайного числа
bool life; // Признак жизни потока
bool run; // Признак выполнения потока
Thread ^thr; // Ссылка на объект потока
int timePeriod; // Временной интервал перемещения
Warehouse ^leftWH; // Ссылка на левый склад
Warehouse ^rightWH;// Ссылка на правый склад
// Конструктор
public:
Lorry (int Number, int Y, int DX, Warehouse ^LeftWH,
Warehouse ^RightWH, ContrlRegion ^Region)
{
number= Number; // Номер объекта компонента
dX= DX; // Приращение объекта компонента
leftRight= true; // Движение слева направо
timePeriod= 100; // Интервал времени объекта компонента
// Определить прямоугольник зоны контроля
region= Region;
rect.Location= region -> Location;
rect.Width= region -> Width;
rect.Height= region -> Height;
inContrl= false; // Объект вне зоны контроля
time= new Random ( ); // Время задержки в зоне контроля
// Реализовать ссылки на объекты складов
leftWH= LeftWH; rightWH= RightWH;
// Определить левую границу пути для объекта компонента
p.X= leftWH -> Location.X+leftWH -> Width + 1; p.Y= Y;
// Создать объект потока
life= false; run= false;
thr= gcnew Thread (gcnew ThreadStart (this, Moving));
}
// Свойство Number
property int get_Number ( ) {return number;}
// Свойство Point
property Point get_Point ( ) {return p;}
// Свойство LeftRight
property void set_LeftRight (bool leftRight)
{
this -> leftRight= leftRight;
}
property bool get_LeftRight ( )
{
return leftRight;
}
// Стартовать поток
void Start ( )
{
life= true; run= true;
thr -> Start ( );
}
// Завершить поток
void Finish ( ) {life= false; thr -> Join ( );}
// Приостановить поток
void Stop ( )
{
if (run)
{
run= false;
thr -> Suspend ( );
}
}
// Возобновить поток
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;
}
// Обслужить в зоне контроля
// Вошли в зону контроля
if (rect.Contains (p) && !inContrl) // Вошли в зону
{
Console::WriteLine ("Вошли в зону");
inContrl= true;
region -> Semaphore -> WaitOne ( );
Thread::Sleep(time -> Next(100, 300));
}
if (!rect.Contains (p) && inContrl) // Вышли из зоны
{
Console::WriteLine ("Вышли из зоны");
inContrl= false;
region -> Semaphore -> ReleaseMutex ( );
}
Thread::Sleep (timePeriod);
p.X += dX;
}
}
};
}
Библиотека ccContrlRegion.dll на языке С++/CLI
///////////////
// C++/CLI Компонент ContrlRegion
#pragma once
#using <mscorlib.dll>
#using <System.Dll>
#using <System.Windows.Forms.Dll>
using namespace System;
using namespace System::Threading;
using namespace System::ComponentModel;
using namespace System::Windows::Forms;
namespace ccContrlRegionDll
{
// Компонент ContrlRegion
public ref class ContrlRegion: public UserControl
{
Mutex ^mutex; // Ссылка на объект мютекса
public:
// Конструктор
ContrlRegion ( )
{
mutex= gcnew Mutex ( );
}
// Свойство Semaphore
property Mutex^ get_Semaphore ( )
{
return mutex;
}
};
}
Библиотека ccWarehouse.dll на языке С++/CLI
///////////////
// C++/CLI компонент Warehouse
#pragma once
#using <mscorlib.dll>
#using <System.Dll>
#using <System.Drawing.Dll>
#using <System.Windows.Forms.Dll>
using namespace System;
using namespace System::Threading;
using namespace System::Drawing;
using namespace System::ComponentModel;
using namespace System::Windows::Forms;
namespace ccWarehouseDll
{
// Класс данных события evFromWarehouse
public ref class WarehouseEventArgs: public EventArgs
{
bool left; // Признак идентификации склада
bool full; // Признак заполненности склада
public:
WarehouseEventArgs (bool left, bool full)
{
this -> left= left; this -> full= full;
}
// Свойство заполнения склада
property bool get_Full ( )
{
return full;
}
// Свойство идентификации склада
property bool get_Left ( )
{
return left;
}
};
// Делегат события о переполнении и опустошении склада
public delegate void DelEvFromWarehouse (Object ^sender,
WarehouseEventArgs *args);
// Интерфейс склада
public interface class IWarehouse
{
void Put ( ); // Поместить груз в склад
void Get ( ); // Получить груз из склада
event DelEvFromWarehouse ^evFromWarehouse; // Ссылка на
// объект события о переполнении и опустошении склада
};
// Компонент склада
public ref class Warehouse: public UserControl,
public IWarehouse
{
bool left; // Признак идентификации склада
int allLoad; // Текущий размер груза в складе
int PartLoad; // Размер груза грузовика
int partLoad; // Получаемая или помещаемая порция груза
int numParts; // Количество порций
int timePeriod; // Время получения или помещения
// порции груза
Thread ^thr; // Ссылка на объект потока
public event DelEvFromWarehouse ^evFromWarehouse; // Ссылка на
// объект события о переполнении и опустошении склада
// Конструктор
Warehouse (bool left, bool full)
{
allLoad= 100; numParts= 5; PartLoad= 10;
this -> left= left; timePeriod= 100;
if (!full) allLoad= 0; // Склад пуст
}
// Поместить груз в склад
void Put ( )
{
if (((100 - allLoad) < PartLoad) && (evFromWarehouse != 0))
{
// Недостаточно места в складе для выгрузки грузовика
WarehouseEventArgs ^wH= gcnew WarehouseEventArgs
(left, true);
evFromWarehouse (this, wH); // Сгенерировать событие
return;
}
// Выгрузить грузовик и увеличить порциями груз склада
// с помощью потока
partLoad= PartLoad; // Определить выгрузку
// Создать поток выгрузки склада
thr= gcnew Thread (gcnew ThreadStart (this, Change));
thr -> Start ( ); // Стартовать поток
thr -> Join ( ); // Подождать завершения потока
}
// Получить груз из склада
void Get ( )
{
if (((allLoad) < PartLoad) && (evFromWarehouse != 0))
{
// Недостаточно груза в складе для загрузки грузовика
WarehouseEventArgs ^wH= new WarehouseEventArgs
(left, false);
evFromWarehouse (this, wH); // Сгенерировать событие
return;
}
// Загрузить грузовик и уменьшить порциями груз склада
// с помощью потока
partLoad= -PartLoad; // Определить выгрузку
// Создать поток загрузки склада
thr= gcnew Thread (new ThreadStart (this, 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); // Завершить критическую секцию
}
// Перерисовать размещение груза в складе
virtual void OnPaint (PaintEventArgs ^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);
}
};
}