Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
КОП-Примеры / Время жизни компонента.doc
Скачиваний:
16
Добавлен:
12.03.2015
Размер:
102.91 Кб
Скачать

225

16. Время жизни объекта компонента

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

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

Если объект компонента наследует класс MarshalByRefObject, создан в приложении сервера и является удалённым объектом разновидности Singleton или активирован клиентом, то время его жизни может быть разным и определяется активностью его использования клиентами, располагающими прокси этого удалённого объекта. Если удалённый объект компонента уже не применяется клиентами, то жизнь его может быть завершена и система .NET Remoting сама удалит его из памяти (управляемой кучи) с помощью распределённого сборщика мусора. Если же потребность в удалённом объекте ещё будет существовать, то его жизнь может быть продлена с помощью средств, предоставляемых системой .NET Remoting. Средства .NET Remoting дают возможность долгосрочной аренды (leasing) удалённого объекта со спонсированием (sponsorship).

Лизинг (lease) – это время, отводимое удалённому объекту до момента, когда он будет удалён системой .NET Remoting из памяти (разрывается связь удалённого объекта с его прокси). Надо заметить, что по умолчанию удалённому объекту устанавливается начальное время лизинга, причём каждый новый вызов удалённого объекта из клиента увеличивает это значение, продлевая тем самым продолжительность жизни объекта. Используя средства .NET Remoting можно установить свой начальный лизинг. Более того, продлить время жизни можно с помощью спонсоров (sponsors), связанных с этим удалённым объектом. Когда завершается лизинг, система .NET Remoting просматривает список спонсоров и удлиняет жизнь удалённого объекта.

Лизинг удаленного объекта компонента

Специальный объект - лизинговый менеджер (a lease manager) домена сервера – выявляет продолжительность жизни удалённых объектов, размещённых в этом домене, и при её завершении некоторым объектом помечает этот объект для удаления сборщиком мусора.

Используя средства .NET Remoting, можно установить свой начальный лизинг. Более того, продлить время жизни можно с помощью спонсоров (sponsors), связанных с этим удалённым объектом. Когда завершается лизинг лизинговый менеджер просматривает список спонсоров для этого объекта. Если спонсоров нет, то объект удаляется из памяти (разрывается связь удалённого объекта с его прокси). Иначе лизинговый менеджер удлиняет жизнь удалённого объекта. Жизнь удалённого объекта также удлиняется каждым вызовом из клиента.

Итак, жизнь удалённого объекта не зависима от жизни клиента или клиентов, но зависит от количества клиентов и использованием этого объекта.

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

Для инициализации лизинга удалённого объекта применяется функция InitializeLifetimeService() класса MarshalByRefObject, который наследует удалённый объект:

public virtual object InitializeLifetimeService ( ); // C#

public: virtual Object^ InitializeLifetimeService ( ); // C++/CLI

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

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

Пример 16.1. Удалённый объект компонента с лизингом.

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

// C# Удалённый компонент

using System;

using System.Runtime.Remoting.Lifetime;

namespace csRemObj_Dll_a_Lease

{

public interface IRemObj

{

int GetAdd (int par);

}

public class RemObj : MarshalByRefObject, IRemObj

{

private int n= 0;

ILease lease;

public RemObj ( )

{

Console.WriteLine ("Constructor");

}

public int GetAdd (int par)

{

n++;

Console.WriteLine ("\nGetAdd n= " +n

+ " par= " + par + " return " + (n+ par));

Console.WriteLine ("lease.CurrentLeaseTime= "

+ lease.CurrentLeaseTime);

return n + par;

}

// Инициализация лизинга удалённого объекта

public override Object InitializeLifetimeService ( )

{

lease= (ILease) base. InitializeLifetimeService ( );

if (lease.CurrentState == LeaseState.Initial)

{

lease.InitialLeaseTime= TimeSpan.FromSeconds (3);

lease.RenewOnCallTime= TimeSpan.FromSeconds (1);

}

return lease;

}

}

}

В примере 16.1 класс RemObj наследует класс MarshalByRefObject, включающий функцию InitializeLifetimeService(). В классе RemObj эта функция переопределяется, устанавливая начальное значение лизинга, равное 3мс, и интервал времени обновления значения лизинга, равный 1мс. Переопределённая функция InitializeLifetimeService() возвращает установленный лизинг lease.

В примере 16.1 функция InitializeLifetimeService() возвращает значение лизинга, которое указывает системе значение лизинга удалённого объекта. Если же возвращаемое значение лизинга нулевое, как в примере 16.4, то время жизни удалённого объекта равно времени жизни приложения сервера, или пока он не будет удален специально. В удалённых объектах разделов 13 и 14 функция InitializeLifetimeService использовалась по умолчанию с нулевым возвращаемым значением (“бесконечная жизнь”).

Приложения сервера и клиента примера 16.2 используют наш изменённый удалённый объект. Клиент пытается применить удалённый объект после исчерпания его лизинга, и он наказан – приложение клиента завершает работу аварийно. Система выбрасывает исключение RemotingException.

Пример 16.2. Сервер и клиент для удалённого объекта компонента с лизингом.

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

// C# Сервер

// Подключить (AddReferance) библиотеку System.Runtime.Remoting.dll.

// Подключить (AddReferance) библиотеку csRemObj_Dlll_a_Lease.dll.

using System;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Http;

using csRemObj_Dll_a_Lease;

namespace csRemObj_Server_SA_Singleton_Lease

{

class RemObjServer

{

static void Main (string[] args)

{

HttpChannel httpChannel= new HttpChannel (8080);

ChannelServices.RegisterChannel (httpChannel);

RemotingConfiguration.RegisterWellKnownServiceType (

typeof (csRemObj_Dll_a_Lease.RemObj),

"RemoteObject",

WellKnownObjectMode.Singleton);

System.Console.WriteLine ("Wait to exit");

System.Console.ReadLine ( );

}

}

}

/*

Result:

Wait to exit

Constructor

GetAdd n= 1 par= 5 return 6

lease.CurrentLeaseTime= 00:00:02.8750000

GetAdd n= 2 par= 10 return 12

lease.CurrentLeaseTime= 00:00:02.8750000

GetAdd n= 3 par= 5 return 8

lease.CurrentLeaseTime= 00:00:01

GetAdd n= 4 par= 10 return 14

lease.CurrentLeaseTime= 00:00:01

GetAdd n= 2 par= 10 return 12

lease.CurrentLeaseTime= 00:00:02.8750000

Constructor

GetAdd n= 1 par= 5 return 6

lease.CurrentLeaseTime= 00:00:03

GetAdd n= 2 par= 10 return 12

lease.CurrentLeaseTime= 00:00:03

*/

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

// C# Клиент

// Подсоединить (AddReference) библиотеку System.Runtime.Remoting.dll и

// подсоединить библиотеку csRemObj_Dll_a.dll.

using System;

using System.Threading;

using System.Runtime.Remoting.Lifetime;

using System.Runtime.Remoting;

using System.Runtime.Remoting.Channels;

using System.Runtime.Remoting.Channels.Http;

using csRemObj_Dll_a_Lease;

namespace csRemObj_Client_a_1_Lease

{

class RemObjClient

{

[STAThread]

static void Main (string[] args)

{

RemObj objServ;

HttpChannel httpChannel= new HttpChannel (0);

ChannelServices.RegisterChannel (httpChannel);

objServ= (RemObj) Activator.GetObject (

typeof (RemObj),

"http://localhost:8080/RemoteObject");

ILease lease;

lease= (ILease)objServ.GetLifetimeService();

Console.WriteLine ("результат objServ.GetAdd (5))= " +

objServ.GetAdd (5));

Console.WriteLine ("результат objServ.GetAdd (10))= " +

objServ.GetAdd (10));

Console.WriteLine ("lease.CurrentLeaseTime: " +

lease.CurrentLeaseTime);

Thread.Sleep (3000);

Console.WriteLine ("результат objServ.GetAdd (5))= " +

objServ.GetAdd (5));

Console.WriteLine ("результат objServ.GetAdd (10))= " +

objServ.GetAdd (10));

Console.WriteLi ne ("lease.CurrentLeaseTime: " +

lease.CurrentLeaseTime);

Thread.Sleep (10000);

Console.WriteLine ("результат objServ.GetAdd (5))= " +

objServ.GetAdd (5));

Console.WriteLine ("результат objServ.GetAdd (10))= " +

objServ.GetAdd (10));

Console.WriteLine ("lease.CurrentLeaseTime: " +

lease.CurrentLeaseTime);

Console.WriteLine ("Press ENTER to exit");

Console.ReadLine ( );

}

}

}

// Результат выполнения клиента csRemObj_Client_a_1_Lease совместно с сер-

// вером

// csRemObj_Server_SA_Singleton_Lease

/*

Result:

результат objServ.GetAdd (5) = 6

результат objServ.GetAdd (10)= 12

lease.CurrentLeaseTime: 00:00:02.8750000

результат objServ.GetAdd (5) = 8

результат objServ.GetAdd (10)= 14

lease.CurrentLeaseTime: 00:00:01

результат objServ.GetAdd (5) = 6

результат objServ.GetAdd (10)= 12

Unhandled Exception: System.Runtime.Remoting.RemotingException: Requested Service not found

. . .

Press ENTER to exit

*/

Приложение клиента примера 16.2 после создания прокси удалённого объекта многократно вызывает его интерфейсную функцию GetAdd() и выдаёт на консоль значение текущего лизинга с интервалом 3 и10 мс. Из результата выполнения приложения сервера и клиента видно, что после исчерпания лизинга наш удалённый объект создаётся заново (Обратите внимание на появление слова Constructor в консольном окне сервера). Это подтверждает тот факт, что удалённый объект разновидности Singleton был уничтожен и теперь создан снова. В виду исчерпания лизинга система .NET Remoting отсоединила удалённый объект от клиента, что вызвало выброс исключения RemotingException и аварийное завершение работы приложения клиента с пояснением, что клиент пытался воспользоваться неустановленной интерфейсной ссылкой objServ.

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

Соседние файлы в папке КОП-Примеры