Сборки, потоки и домены приложений. Лекция #5

Содержание

Слайд 2

Common Object Model Повторное использование кода Создание COM-серверов и регистрация их

Common Object Model

Повторное использование кода
Создание COM-серверов и регистрация их в реестре

(HREY_CLASSES_ROOT)
Проблема версий COM
Запись в реестре и сам двоичный файл COM не связаны друг с другом
Слайд 3

Обзор сборок .NET Приложение .NET – объединение любого количества сборок Сборка

Обзор сборок .NET

Приложение .NET – объединение любого количества сборок
Сборка – это

двоичный файл (DLL или EXE), который содержит номер версии, метаданные, а также типы и дополнительные ресурсы
Манифест – набор метаданных о самой сборке
Слайд 4

Обзор сборок .NET Логическое представление сборки (классы, интерфейсы, ресурсы, делегаты) Физическое

Обзор сборок .NET

Логическое представление сборки (классы, интерфейсы, ресурсы, делегаты)
Физическое представление (набор

модулей – файлов)
Сборки обеспечивают повторное использование кода, написанного на любом языке .NET
Сборки – контейнеры для типов (не будет конфликта имен)
Разные версии сборок могут выполнятся одновременно
Слайд 5

Создание однофайловой сборки

Создание однофайловой сборки

Слайд 6

Добавление ссылки на внешнюю сборку

Добавление ссылки на внешнюю сборку

Слайд 7

Библиотека кода - CarLibary namespace CarLibrary { using System; public enum

Библиотека кода - CarLibary

namespace CarLibrary
{ using System;
public enum EngineState // Для

двух возможных состояний двигателя
{ engineAlive,
engineDead
}
public abstract class Car // Абстрактный класс — базовый в нашей будущей иерархии
{
// Защищенные данные о состоянии
protected string petName;
protected short currSpeed;
protected short maxSpeed;
protected EngineState egnState;
public Car() {egnState = EngineState.engineAlive;}
public Car(string name, short max, short curr)
{ egnState = EngineState.EngineAlive;
petName = name; maxSpeed = max; currSpeed = curr; }
public string PetName { get { return petName; } set { petName = value; } }
public short CurrSpeed { get { return currSpeed; } set { currSpeed = value; } }
public short MaxSpeed { get {return maxSpeed; } }
public EngineState EngineState { get { return egnState; } }
public abstract void TurboBoost();
}}
Слайд 8

Реализация конкретных классов SportsCar и MiniVan namespace CarLibrary { using System;

Реализация конкретных классов SportsCar и MiniVan

namespace CarLibrary
{ using System;
using System.Windows.Forms;

// Чтобы можно было использовать MessageBox
public class SportsCar : Car // Определение класса SportsCar
{
// Конструкторы
public SportsCar(){}
public SportsCar(string name, short max, short curr) : base (name, max, curr) {}
// Специфическая реализация метода TurboBoost()
public override void TurboBoost()
{
MessageBox.Show("Ramming speed!", "Faster is better...");
}
}
// Определение класса MiniVan
public class Minivan : Car
{
// Конструкторы
public MiniVan(){}
public MiniVan(string name, short max, short curr) : base (name, max, curr){}
// Реализация метода TurboBoost()
{
// Мини-вэны разгоняются неважно
egnState = EngineState.engineDead;
MessageBox.Show("Time to call AAA", "Your car is dead");
}
}
}
Слайд 9

Клиентское приложение При добавлении в проекте ссылки на сборку в каталог DEBUG полностью копируется DLL-файл

Клиентское приложение

При добавлении в проекте ссылки на сборку в каталог DEBUG

полностью копируется DLL-файл
Слайд 10

Клиентское приложение // Первый опыт использования собственной библиотеки кода namespace CSharpCarClient

Клиентское приложение

// Первый опыт использования собственной библиотеки кода
namespace CSharpCarClient
{
using System;
// Используем

типы из CarLibrary
using CarLibrary;
public class CarClient
{
public static int Main(string[] args)
{
// Создаем автомобиль спортивной модели
SportsCar viper = new SportsCar("Viper", 240, 40);
viper.TurboBoost();
// Создаем мини-вэн
MiniVan mv = new MiniVan();
mv.TurboBoost();
return 0;
}
}
}
Слайд 11

Манифест

Манифест

Слайд 12

Метаданные типов

Метаданные типов

Слайд 13

Частные сборки private или shared Находятся в каталоге приложения или в

Частные сборки

private или shared
Находятся в каталоге приложения или в подкаталогах
Можно переносить

каталог с приложением
Можно просто все удалить
Слайд 14

Алгоритм поиска В каталоге приложения dll В каталоге приложения exe Конфигурационный файл

Алгоритм поиска

В каталоге приложения dll
В каталоге приложения exe
Конфигурационный файл

Слайд 15

Конфигурационный файл CSSharpClient.exe → CSSharpClient.exe.config

Конфигурационный файл








CSSharpClient.exe →

CSSharpClient.exe.config
Слайд 16

Сборки для общего доступа Global Assembly Cache (GAC) C:\WINDOWS\Assembly Дополнительная информация

Сборки для общего доступа

Global Assembly Cache (GAC)
C:\WINDOWS\Assembly
Дополнительная информация о версии –

общее или сильное имя
Слайд 17

«Сильные» имена сборок Дружественное текстовое имя и «культурная информация» Идентификатор версии Пара открытый/закрытый ключ Цифровая подпись

«Сильные» имена сборок

Дружественное текстовое имя и «культурная информация»
Идентификатор версии
Пара открытый/закрытый ключ
Цифровая

подпись
Слайд 18

Текст сборки using System; using System.Windows.Forms; namespace SharedAssembly { public class

Текст сборки

using System;
using System.Windows.Forms;
namespace SharedAssembly
{
public class VWMiniVan
{
public VWMiniVan(){}
public void Play60sTunes()
{
MessageBox.Show("What

a loooong, strange trip it's been...");
}
private bool isBustedByTheFuzz = false;
public bool Busted
{
get { return isBustedByTheFuzz; }
set { isBustedByTheFuzz = value; }
}
}
}
Слайд 19

Создание пары открытый/закрытый ключ

Создание пары открытый/закрытый ключ

Слайд 20

Установка сборки в GAC Утилита gacutil.exe Перетащить мышкой

Установка сборки в GAC

Утилита gacutil.exe
Перетащить мышкой

Слайд 21

Использование общей сборки в приложении namespace SharedLibUser { using System; using

Использование общей сборки в приложении

namespace SharedLibUser
{
using System;
using SharedAssembly;
public class SharedAsmUser
{
public static

int Main(string[] args)
{
try
{
VWMiniVan v = new VWMiniVan();
v.Play60sTunes();
}
catch(TypeLoadException e)
{
// Не могу найти сборку!
Console.WriteLine(e.Message);
}
return 0;
}
}
}
Слайд 22

Анатомия версии сборки Номер основной версии (Несовместимые) Номер дополнительной версии (Несовместимые)

Анатомия версии сборки

Номер основной версии (Несовместимые)
Номер дополнительной версии (Несовместимые)
Номер редакции (Возможно

совместимые)
Номер сборки (Quick Fix Engineering)
Слайд 23

Запись информации о версии

Запись информации о версии

Слайд 24

Загрузка разных версий сборок По умолчанию: первые две цифры запрашиваемые, вторые

Загрузка разных версий сборок

По умолчанию: первые две цифры запрашиваемые, вторые –

последние по номеру
Явная загрузка нужной версией: управление из файла *.config





publicKeyToken="6c0646f072c6fe39"
culture=""/>
newVersion="2.0.0.0"/>




Слайд 25

Домены приложения Процесс состоит из одного или нескольких доменов В рамках

Домены приложения

Процесс состоит из одного или нескольких доменов
В рамках домена работает

один или несколько потоков
Домен приложения полностью изолирует используемые в его рамках ресурсы от других доменов (за исключением удаленного доступа к данным)
Слайд 26

Тип AppDomain

Тип AppDomain

Слайд 27

Работаем с доменами приложения namespace MyAppDomain { using System; using System.Windows.Forms;

Работаем с доменами приложения

namespace MyAppDomain
{
using System;
using System.Windows.Forms;
// Это

пространство имен требуется для работы с типом Assembly
using System.Reflection;
public class MyAppDomain
{
public static void PrintAllAssemblies()
{
// Получаем список всех загруженных в текущий домен приложения сборок
AppDomain ad = AppDomain.CurrentDomain;
Assembly[] loadedAssemblies = ad.GetAssemblies();
Console.WriteLine("Here are the assemblies loaded in " + "this appdomain\n");
// Теперь выводим полное имя для каждой сборки
foreach(Assembly a in loadedAssemblies)
Console.WriteLine(a.FullName);
}
public static int Main(string[] args)
{
// Производим принудительную загрузку System.Windows.Forms.dll
MessageBox.Show("Loaded System.Windows.Forms.dll");
PrintAllAssemblies();
return 0;
}
}
}
Слайд 28

Пространство имен System.Threading Interlocked – синхронизация общего доступа к данным Monitor

Пространство имен System.Threading

Interlocked – синхронизация общего доступа к данным
Monitor – синхронизация

потоковых объектов
Mutex – примитив синхронизации
Thread – поток, работающий в .NET
ThreadPool – управление набором взаимосвязанных потоков
Timer – определяет делегат, который будет вызван в указанное время
WaitHandle – представляет все объекты синхронизации
ThreadStart – делегат со ссылкой на метод, который должен быть вызван перед запуском потока
TimerCallback – делегат для объектов Timer
WaitCallback – делегат для рабочих элементов ThreadPool
Слайд 29

Статические члены класса Thread

Статические члены класса Thread

Слайд 30

Обычные члены класса Thread

Обычные члены класса Thread

Слайд 31

Запуск вторичных потоков // вспомогательный класс internal class WorkerClass { public

Запуск вторичных потоков

// вспомогательный класс
internal class WorkerClass
{
public void DoSomeWork()
{
// Выводим на

консоль информацию о рабочем потоке
Console.WriteLine("ID of worker thread is: {0}",
Thread.CurrentThread.GetHashCode());
// Выполняем некоторые действия
Console.Write("Worker says: ");
for (int i = o; i < 10; i++)
{
Console.Write(i+ ", ");
}
Console.WriteLine();
}
}
Слайд 32

Запуск вторичных потоков using System.Threading; public class MainClass { public static

Запуск вторичных потоков

using System.Threading;
public class MainClass
{
public static

int Main(string[] args)
{
// Выводим на консоль информацию о текущем потоке
Console.WriteLine("ID of primary thread is: {0}",
Thread.CurrentThread.GetHashCode());
// Создаем объект класса WorkerClass
WorkerClass w = new WorkerClass();
// А теперь создаем и запускаем фоновый поток
Thread backgroundThread =
new Thread(new ThreadStart(w.DoSomeWork));
backgroundThread.Start();
return 0;
}
}
Слайд 33

Именованные потоки using System.Threading; public class MainClass { public static int

Именованные потоки

using System.Threading;
public class MainClass
{
public static int

Main(string[] args)
{
// Присваиваем имя текущему потоку
Thread primaryThread = Tread.CurrentThread;
primaryThread.Name = "Boss man";
Console.WriteLine("Id of {0} is {1}", primaryThread.Name,
promaryThread.gethascode());
// …
return 0;
}
}
Слайд 34

Параллельная работа потоков public static int Main(string[] args) { Console.Write("Do you

Параллельная работа потоков

public static int Main(string[] args)
{
Console.Write("Do you want [1]

or [2] threads? ");
string threadCount = Console.ReadLine();
// Создаем объект класса WorkerClass
WorkerClasss w = new WorkerClass();
// Создаем дополнительный поток, только если это указано
if(threadCount = = "2")
{ // Создаем дополнительный поток
Thread backgroundThread = new Thread(new ThreadStart(w.DoSomeWork));
backgroundThread.Start();
}
else
w.DoSomeWork();
// Даем первичному потоку свое задание
MessageBox.Show("I'm busy!");
return 0;
}
Слайд 35

Как «усыпить» поток internal class WorkerClass { public void DoSomeWork() {

Как «усыпить» поток

internal class WorkerClass
{
public void DoSomeWork()
{
// Выводим информацию

о рабочем потоке
Console.WriteLine("ID of worker thread is: {0}",
Thread.CurrentThread.GetHashCode());
// Делаем работу "с перекурами"
Console.Write("Worker says: ");
for(int i = 0; i < 5; i++)
{
Console.WriteLine(i + ", ");
Thread.Sleep(5000);
}
Console.WriteLine();
}
}
Слайд 36

Одновременный доступ к данным из разных потоков public class MainClass {

Одновременный доступ к данным из разных потоков

public class MainClass
{
public static

int Main(string[] args)
{
// Создаем единственный объект класса WorkerClass
WorkerClass w = new WorkerClass();
// Создаем три отдельных потока, каждый из которых производит вызов
// к одному и тому же объекту
Thread workerThreadA = new Thread(new ThreadStart(w.DoSomeWork));
Thread workerThreadB = new Thread(new ThreadStart(w.DoSomeWork));
Thread workerThreadC = new Thread(new ThreadStart(w.DoSomeWork));
// Теперь запускаем все три потока
WorkerThreadA.Start();
WorkerThreadB.Start();
WorkerThreadC.Start();
return 0;
}
}
Слайд 37

Ключевое слово lock internal class WorkerClass { public void DoSomeWork() {

Ключевое слово lock

internal class WorkerClass
{
public void DoSomeWork()
{
// Только

один поток в конкретный момент времени сможет
// выполнять этот код!
lock(this)
{
// Делаем все ту же работу
for(int i=0; i < 5; i++)
{
Console.WriteLine("Worker says: {0},", i);
}
}
}
}
Слайд 38

Использование System.Threading.Monitor internal class WorkerClass { public void DoSomeWork() { //

Использование System.Threading.Monitor

internal class WorkerClass
{
public void DoSomeWork()
{
// Определяем элемент

для мониторинга в целях синхронизации
Monitor.Enter(this);
try
{
// Выполнить работу...
for(int i = 0; i < 5; i++)
{
Console.WriteLine("Worker says: {0},", i);
}
}
finally
{
// Была ошибка или нет, а из монитора придется выйти
Monitor.Exit(this);
}
}
}
Слайд 39

Опасность одновременного изменения переменной public class IHaveNoIdea { private long refCount

Опасность одновременного изменения переменной

public class IHaveNoIdea
{
private long refCount = 0;
public void

AddRef()
{ ++refCount; }
public void Release()
{
if(--refCount == 0)
{
GC.Collect();
}
}
}