- •Сборки (assembly) в среде .Net. Проблема версионности сборок и ее решение.
- •Номер версии в .Net
- •Сведения о версии
- •Номер версии сборки
- •Информационная версия сборки
- •Общая система типов данных в среде .Net. Размерные и ссылочные типы данных. Типы, переменные и значения
- •Пользовательские типы
- •Система общих типов cts
- •Ссылочные типы
- •Типы литеральных значений
- •Неявные типы, анонимные типы и типы, допускающие значение null
- •Упаковка и распаковка размерных типов данных в среде .Net.
- •Производительность
- •Упаковка–преобразование
- •Распаковка-преобразование
- •Ссылочные типы данных. Объектная модель в среде .Net и языке c#.
- •Модели ручной и автоматической утилизации динамической памяти, их сравнительная характеристика. Модель с ручным освобождением памяти
- •Модель с автоматической «сборкой мусора»
- •Модель автоматической утилизации динамической памяти, основанная на сборке мусора. Проблема недетерминизма.
- •Модель автоматической утилизации динамической памяти, основанная на аппаратной поддержке (тегированной памяти).
- •Сборка мусора в среде .Net. Построение графа достижимых объектов.
- •Сборка мусора в среде .Net. Механизм поколений объектов.
- •Модель детерминированного освобождения ресурсов в среде .Net. Интерфейс iDisposable и его совместное использование с завершителем (методом Finalize).
- •«Мягкие ссылки» и кэширование данных в среде .Net.
- •Краткие и длинные слабые ссылки
- •Краткая ссылка
- •Длинная ссылка
- •Правила использования слабых ссылок
- •Динамические массивы в среде .Net и языке c#.
- •Приведение типов в массивах
- •Все массивы неявно реализуют /Enumerable, /Collection и iList
- •Передача и возврат массивов
- •Создание массивов с ненулевой нижней границей
- •Производительность доступа к массиву
- •Небезопасный доступ к массивам и массивы фиксированного размера
- •Делегаты в среде .Net и механизм их работы. Знакомство с делегатами
- •Использование делегатов для обратного вызова статических методов
- •Использование делегатов для обратного вызова экземплярных методов
- •Правда о делегатах
- •Использование делегатов для обратного вызова множественных методов (цепочки делегатов)
- •Поддержка цепочек делегатов в с#
- •Расширенное управление цепочкой делегатов
- •Упрощение синтаксиса работы с делегатами в с#
- •Упрощенный синтаксис № 1: не нужно создавать объект-делегат
- •Упрощенный синтаксис № 2: не нужно определять метод обратного вызова
- •Упрощенный синтаксис № 3: не нужно определять параметры метода обратного вызова
- •Упрощенный синтаксис № 4: не нужно вручную создавать обертку локальных переменных класса для передачи их в метод обратного вызова
- •Делегаты и отражение
- •События в среде .Net; реализация событий посредством делегатов. События
- •Этап 1: определение типа, который будет хранить всю дополнительную информацию, передаваемую получателям уведомления о событии
- •Этап 2: определение члена-события
- •Этап 3: определение метода, ответственного за уведомление зарегистрированных объектов о событии
- •Этап 4: определение метода, транслирующего входную информацию в желаемое событие
- •Как реализуются события
- •Создание типа, отслеживающего событие
- •События и безопасность потоков
- •Явное управление регистрацией событий
- •Конструирование типа с множеством событий
- •Исключительные ситуации и реакция на них в среде .Net. Достоинства
- •Механика обработки исключений
- •Блок try
- •Блок catch
- •Блок finally
- •Генерация исключений
- •Определение собственных классов исключений
- •Исключения в платформе .Net Framework
- •Исключения и традиционные методы обработки ошибок
- •Управление исключениями средой выполнения
- •Фильтрация исключений среды выполнения
- •21 Средства многопоточного программирования в среде .Net. Автономные потоки. Пул потоков.
- •Создание и использование потоков
- •Запуск и остановка потоков
- •Методы управления потоками
- •Безопасные точки
- •Свойства потока
- •Потоки Windows в clr
- •К вопросу об эффективном использовании потоков
- •Пул потоков в clr
- •Ограничение числа потоков в пуле
- •22. Асинхронные операции в среде .Net. Асинхронный вызов делегатов.
- •23. Синхронизация программных потоков в среде .Net. Блокировки.
- •Двойная блокировка
- •Класс ReaderWriterLock
- •Использование объектов ядра Windows в управляемом коде
- •Вызов метода при освобождении одного объекта ядра
- •24. Синхронизация программных потоков в среде .Net. Атомарные (Interlocked-операции). Семейство lnterlocked-методов
- •25. Прерывание программных потоков в среде .Net. Особенности исключительной ситуации класса ThreadAbortException.
- •26. Мониторы в среде .Net. Ожидание выполнения условий с помощью методов Wait и Pulse. Класс Monitor и блоки синхронизации
- •«Отличная» идея
- •Реализация «отличной» идеи
- •Использование класса Monitor для управления блоком синхронизации
- •Способ синхронизации, предлагаемый Microsoft
- •Упрощение кода c# при помощи оператора lock
- •Способ синхронизации статических членов, предлагаемый Microsoft
- •Почему же «отличная» идея оказалась такой неудачной
- •Целостность памяти, временный доступ к памяти и volatile-поля
- •Временная запись и чтение
- •Поддержка volatile-полей в с#
- •27. Асинхронный вызов делегатов.
- •Общие типы (Generics)
- •Инфраструктура обобщений
- •Открытые и закрытые типы
- •Обобщенные типы и наследование
- •Проблемы с идентификацией и тождеством обобщенных типов
- •«Распухание» кода
- •Обобщенные интерфейсы
- •Обобщенные делегаты
- •Обобщенные методы
- •Логический вывод обобщенных методов и типов
- •Обобщения и другие члены
- •Верификация и ограничения
- •Основные ограничения
- •Дополнительные ограничения
- •Ограничения конструктора
- •Другие вопросы верификации
- •Приведение переменной обобщенного типа
- •Присвоение переменной обобщенного типа значения по умолчанию
- •Сравнение переменной обобщенного типа с null
- •Сравнение двух переменных обобщенного типа
- •Использование переменных обобщенного типа в качестве операндов
- •Преимущества использования общих типов
- •29. Итераторы в среде .Net. Создание и использование итераторов.
- •Общие сведения о итераторах
22. Асинхронные операции в среде .Net. Асинхронный вызов делегатов.
23. Синхронизация программных потоков в среде .Net. Блокировки.
Существует несколько способ синхронизации потоков в .Net. Возможны следующие варианты:
lnterlocked-методы
Мониторы
AutoResetEvents
Двойная блокировка
ReaderWriterLock
Использование объектов ядра
Двойная блокировка
Существует способ, известный как блокировка с двойной проверкой. Этот способ используется, если нужно отложить создание singleton-объекта до тех пор, пока приложение не запросит его [иногда это называют отложенной инициализацией]. Если приложение не запросит объект, он никогда не будет создан, что позволяет экономить время и память. Возможность возникновения проблем появляется, когда несколько потоков одновременно запрашивают singleton-объект. В этом случае нужно использовать какую-либо синхронизацию потоков, чтобы singleton-объект создавался только раз.
Вот пример кода, показывающий, как применять этот способ блокировки в C#:
public sealed class Singleton
{
// Объект s_lock требуется для обеспечения безопасности в многопоточной среде.
// Наличие этого объекта предполагает, что для создания singleton-объекта требуется
// больше ресурсов, чем для создания объекта System.Object, и что его создание
// может вовсе не понадобиться. В противном случае проще и эффективнее просто создать
// singleton-объект в конструкторе класса.
private static Object s_lock = new Object();
// Временные операции в модели памяти CLR не требуются, но они обязательны в
// модели памяти ЕСМА. Чтобы соответствовать стандарту, я включил ее сюда.
private static volatile Singleton s_value;
// Закрытый конструктор не позволяет создавать экземпляры любому.
// не относящемуся к классу коду.
private Singleton() { }
// Открытое статическое свойство,
// возвращающее singleton-объект (который создается при необходимости).
public static Singleton Value
{
get
{
// Был ли уже создан singleton-объект?
if (s_value == null)
{
// Нет, только один поток должен создавать его.
lock (s_lock)
{
// Создал ли его другой поток?
if (s_value == null)
{
// Нет, все в порядке, этот поток создаст его.
// Временность операций гарантирует, что все поля singleton-объекта
// (инициализированные конструктором) будут очищены, прежде чем
// другие потоки увидят ссылку на этот объект.
s_value = new Singleton();
// Возвращение ссылки на singleton-объект.
return s_value;
}
}
}
}
}
}
Принцип работы блокировки с двойной проверкой заключается в том, что вызов метода-аксессора get быстро проверяет поле s_value, выясняя, был ли объект уже создан, и если да, метод возвращает ссылку на него. Изюминка здесь в том, что после создания объекта синхронизация потоков не требуется, и приложение будет работать очень быстро. С другой стороны, если первый поток, вызвавший метод получения доступа к свойству value, увидит, что объект не был создан, он устанавливает блокировку синхронизации потоков, чтобы только один поток мог создать singleton-объект. Это значит, что производительность страдает только однажды, при первом запросе singleton-объекта.
Теоретически возможно, что JIT-компилятор считает значение поля s_value из регистра процессора в начале метода-аксессора get и просто запросит этот регистр при проверке условия второго оператора if. Если JIT-компилятор создаст именно такой код, значение во втором операторе if всегда будет равно true и singleton-объект может быть создан несколькими потоками. Это совсем не то, что нужно. Однако JIT-компилятор знает, что поле, помеченное ключевым словом volatile, кешировать не надо. Кроме того, JIT-компилятор всегда заново считывает поле, к которому обращается после вызова метода, если этот метод включает операции временного чтения или записи (например, Monitor.Enter или Monitor.Exit).
Вот гораздо более простая версия класса Singleton, которая ведет себя так же, как и предыдущая версия, но в ней не используется блокировка с двойной проверкой.
public sealed class Singleton
{
private static Singleton s_value = new Singleton();
// Закрытый конструктор не позволяет какому-либо внешнему коду
// создавать экземпляры класса.
private Singleton() { }
// Открытое статическое свойство, возвращающее singleton-объект.
public static Singleton Value
{
get
{
// Возвращение ссылки на singleton-объект.
return s_value;
}
}
}
CLR автоматически вызывает конструктор класса типа при первой попытке получить доступ к члену этого класса, поэтому, когда поток в первый раз запросит метод-аксессор get свойства Value объекта Singleton, CLR автоматически вызовет конструктор класса, который создаст экземпляр объекта. Кроме того, CLR уже обеспечил безопасность конструктора класса в отношении синхронизации потоков.
Блокировка с двойной проверкой менее эффективна, чем использование конструктора класса, поскольку приходится создавать собственный объект блокировки (в конструкторе класса) и самостоятельно писать весь дополнительный код для блокировки.
Блокировка с двойной проверкой интересна только в том случае, если класс имеет много членов и нужно создавать singleton-объект, только когда вызывается один из членов. Кроме этого, чтобы получить выигрыш, создание singleton-объекта должно быть намного более затратным, чем создание объекта, используемого для блокировки.