Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Учебное пособие 1082

.pdf
Скачиваний:
4
Добавлен:
30.04.2022
Размер:
753.13 Кб
Скачать

// идентификатор и имя каждого процесса foreach (var p in runmngProcs)

{

string info = string.Format("-> PID: {0}\tName: {1}", p.Id, p.ProcessName);

Console.WriteLine(info);

}

Console.WriteLine("************************************\n");

}

static void Main()

{

Console.WriteLine("*****Процессы*****");

ListAllRunningProcesses();

Console.ReadLine();

}

Статический метод Process.GetProcessById() получает информацию по конкретному объекту Process через идентификатор процесса (PID).

В случае запроса несуществующего PID генерируется исключение ArgumentException.

Пример получения информации об объекте Process с идентификатором 896 [1 – 3].

// если процесс 896 не существует, генерируется исключение static void GetSpeciflcProcess()

{

Process theProc = null; try

{

theProc = Process.GetProcessByld(896);

}

catch(ArgumentException ex)

{

Console.WriteLine(ex.Message);

}

}

29

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

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

Пример функции перечисления модулей в процессе на основе PID.

static void EnumModsForPid (int pID)

{

Process theProc = null; try

{

theProc = Process.GetProcessByld(pID);

}

catch(ArgumentException ex)

{

Console.WriteLine(ex.Message);

return;

}

Console.WriteLine(“Модули для процесса: {0}", theProc.ProcessName);

try

{

ProcessModuleCollection theMods = theProc.Modules; foreach(ProcessModule pm in theMods)

{

string info = string.Format("-> Имя модуля: {0}“, pm.ModuleName);

Console.WriteLine(info);

}

}

catch (ArgumentException ex)

{Console.WriteLine(ex.Message);

return;

}

}

30

.NET позволяет программно смотреть домены приложений, создавать и выгружать домены приложений во время выполнения, загружать в домены приложений сборки с применением класса AppDomain (табл. 4) из пространства имен

System, из сборки mscorlib. dll.

 

Таблица 4

 

 

 

Метод

Описание

 

 

 

 

CreateDomain()

Статический метод, создает новый до-

 

 

мен приложения в текущем процессе

 

 

 

 

Createlnstance()

Создает экземпляр типа из внешней

 

 

сборки после загрузки соответствующей

 

 

сборки в вызывающий домен приложе-

 

 

ния

 

ExecuteAssembly()

Запускает сборку *.ехе внутри домена

 

 

приложения за счет предоставления

 

 

имени её файла

 

GetAssemblies()

Какие сборки .NET были загружены в

 

 

домен приложения (двоичные файлы

 

 

СОМ и С игнорируются)

 

GetCurrentThreadld()

Статический метод, возвращает иден-

 

 

тификатор активного потока в текущем

 

 

домене приложения

 

Load()

Динамическая загрузка сборки в теку-

 

 

щий домен приложения

 

Unload()

Статический метод выгрузки опреде-

 

 

лённого домена приложения из кон-

 

 

кретного процесса

 

К используемому по умолчанию домену приложения можно получить доступ в своём приложении по статическому свойству AppDomain.CurrentDomain (табл. 5).

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

31

 

 

 

 

Таблица 5

 

 

 

 

 

Свойство

 

Описание

 

 

 

 

 

BaseDirectory

Извлекает путь к каталогу поиска сборок

 

 

 

 

 

 

CurrentDomain

Статическое

свойство

идентификации

 

 

домена приложения для выполняющего-

 

 

ся в текущий момент потока

 

 

FriendlyName

Получает дружественное имя текущего

 

 

домена приложения

 

 

 

MonitoringIsEnabled

Получает/устанавливает значение для

 

 

указания работы функции отслеживания

 

 

использования ресурсов ЦП и памяти

 

 

для текущего процесса. После включе-

 

 

ния функции для процесса отключить ее

 

 

нельзя

 

 

 

 

SetupInformation

Извлекает детали конфигурации домена

 

 

приложения

в

виде

объекта

 

 

AppDomainSetup

 

 

 

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

static void Main()

{

Console.WriteLine ("***** Домен по умолчанию *****\n");

DisplayDADStats();

Console.ReadLine();

}

private static void DisplayDADStats()

{

//доступ к домену приложения текущего потока по умолчанию

AppDomain defaultAD = AppDomain.CurrentDomain;

//дружественное имя

Console.WriteLine(“Имя домена: {0}", defaultAD.FriendlyName);

32

// идентификатор

Console.WriteLine("ID домена: {0}", defaultAD.Id); // используется ли по умолчанию

Console.WriteLine(“Домен по умолчанию? : {0}", defaultAD.IsDefaultAppDomain());

// базовый каталог

Console.WriteLine(“Директория домена: {0}", defaultAD.BaseDirectory);

}

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

AssemblyLoad().

Событие имеет тип делегата

AssemblyLoadEventHandler(), который указывает на любой метод, принимающий System.Object в первом параметре, а AssemblyLoadEventArgs во втором.

Метод InitDAD() инициализирует домен по умолчанию при обработке события AssemblyLoad с помощью лямбдавыражения

private static void InitDAD()

{

//вывод имени любой сборки, загружаемой в домен приложения

//после его создания

AppDomain defaultAD = AppDomain.CurrentDomain; defaultAD.AssemblyLoad += (o, s) =>

{

Console.WriteLine("{0} загружена", s.LoadedAssembly.GetName().Name);

};

}

33

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

Методу AppDomain.CreateDomain() передается дружест-

венное имя создаваемого домена приложения [1 – 3].

static void Main()

{

Console.WriteLine ("***Загруженные в домен сборки *****\n");

//отображение всех сборок, загруженных в домен по умолчанию

AppDomain defaultAD = AppDomain.CurrentDomain; ListAllAssembliesInAppDomain(defaultAD);

//создание нового домена приложения

MakeNewAppDomain();

Console.ReadLine();

}

private static void MakeNewAppDomain()

{

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

//перечисление всех загруженных в него сборок

AppDomain newAD = AppDomain.CreateDomain("SecondAppDomain"); ListAllAssembliesInAppDomain(newAD);

}

static void ListAllAssembliesInAppDomain(AppDomain ad)

{

// список всех загруженных сборок, в домен по умолчанию var loadedAssemblies = from a in ad.GetAssemblies()

orderby a.GetName().Name select a;

Console.WriteLine("*** Сборка загружена в {0} *****\n",

ad.FriendlyName); foreach (var a in loadedAssemblies)

{

Console. WriteLine (“-> Имя: {0}",

34

a.GetName().Name);

Console. WriteLine (“-> Версия: {0}\n", a.GetName().Version);

}

}

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

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

AppDomain.Load().

Существует метод AppDomain.ExecuteAssembly(), кото-

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

Main().

Пример, загружающий сборку Shapes.dll в новый вторичный домен приложения [3]. Библиотеку надо скопировать в папку bin\Debug текущего приложения.

private static void MakeNewAppDomain()

{

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

AppDomain newAD = AppDomain.CreateDomain("SecondAppDomain"); try

{

//загрузка в новый домен сборки Shapes.dll

newAD.Load("Shapes");

}

catch (FileNotFoundException ex)

{

Console.WnteLine(ex.Message);

}

// вывод списка всех сборок

ListAllAssembliesInAppDomain(newAD);

}

Выгружать отдельные сборки .NET в CLR не разрешено.

35

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

Вместе с доменом приложения будут выгружаться и все содержащиеся в нем сборки.

Тип AppDomain имеет событие DomainUnload, которое срабатывает при выгрузке специального домена приложения из содержащего его процесса. Событие ProcessExit срабатывает при выгрузке из процесса используемого по умолчанию домена, поэтому и завершение самого процесса.

Модифицируем метод MakeNewAppDomain().

private static void MakeNewAppDomain()

{

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

AppDomain newAD = AppDomain.CreateDomain("SecondAppDomain"); newAD.DomainUnload += (o, s) =>

{

Console.WriteLine(“Второй домен выгружен!");

}; try

{

//загрузка в новый домен сборки Shapes.dll

newAD.Load(“Shapes");

}

catch (FileNotFoundException ex)

{

Console.WriteLine(ex.Message);

}

//вывод списка всех сборок

ListAllAssembliesInAppDomain(newAD);

//уничтожение домена приложения

АррDomain.Unload(newAD) ;

}

36

В .NET не существует прямого соответствия между доменами приложений и потоками [1].

Фактически определенный AppDomain может иметь несколько потоков, выполняющихся в каждый конкретный момент времени.

Конкретный поток не привязан к одному домену приложений на протяжении своего времени существования.

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

Но один поток не работает в более, чем одном домене приложений сразу.

Чтобы программно получить доступ к AppDomain, в котором работает текущий поток, вызывается статический метод

Thread.GetDomain().

static void ExtractAppDomainHostingThread()

{

// получить AppDomain, в котором работает текущий поток

AppDomain ad = Thread.GetDomain();

}

Особенности работы с делегатами

Простой способ создания потока – использование делегата асинхронным образом [1 - 3].

Делегат – аналог безопасных типов ссылок на методы. Класс Delegate поддерживает асинхронный вызов мето-

дов, т.е. делегат создает отдельный поток, невидимый нами. Это главное преимущество платформы .NET, если поток

создается для вызова методов в асинхронном режиме. Рассмотрим делегат BinaryOp.

public delegate int BinaryOp(int x, int y);

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

37

После компиляции сборка с определением этого делегата будет содержать определение класса, сгенерированного динамически при построении проекта на основе объявления делегата.

Пример [3].

public sealed class BinaryOp : System.MulticastDelegate

{

public BinaryOp(object target, uint functionAddress); public void Invoke(int x, int y);

public IAsyncResult Beginlnvoke(int x, int y, AsyncCallback cb, object state);

public int Endlnvoke(IAsyncResult result);

}

При объявлении делегата .NET компилятор С# строит запечатанный класс – наследник System.MulticastDelegate (на-

следник System.Delegate).

Сгенерированный Invoke() используется для вызова ме-

тода в синхронном режиме.

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

Метод Invoke() не нужно вызывать в коде напрямую – он вызывается неявно, при применении обычного синтаксиса вызова метода.

Пример вызова статического метода Add() в синхронном (блокирующем) режиме [3].

namespace SyncDelegateReview

{

public delegate int BinaryOp(int x, int y); class Program

{

static void Main()

{

Console.WriteLine ("***** Синхронный вызов делегата *****");

// вывести идентификатор выполняющегося потока

38