- •Сборки (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. Создание и использование итераторов.
- •Общие сведения о итераторах
26. Мониторы в среде .Net. Ожидание выполнения условий с помощью методов Wait и Pulse. Класс Monitor и блоки синхронизации
В Win32 API структура CRITICAL_SECTION и связанные с ней функции предлагают самый быстрый и эффективный способ синхронизации потоков для взаимоисключающего доступа к общему ресурсу, когда все потоки работают в одном процессе. Взаимоисключающий доступ к общему ресурсу нескольких потоков — это, наверное, самая распространенная форма синхронизации потоков. CLR не предоставляет структуру CRITICAL_SECTION, но предлагает похожий механизм, позволяющий организовать взаимоисключающий доступ к ресурсу в наборе потоков одного процесса. Используя этот механизм, задействуют класс System.Threading.Monitor и блоки синхронизации.
«Отличная» идея
CLR специалисты Microsoft решили создать механизм, который позволил бы разработчикам просто и без усилий синхронизировать доступ к состоянию объекта.
Основная идея такова: с каждым объектом в куче связана структура данных (аналогично структуре CRITICAL SECTION в Win32), которую можно использовать как блокировку синхронизации. В библиотеке FCL (Framework Class Library) есть методы, позволяющие получить ссылку на объект. Эти методы должны использовать структуру данных объекта для установки и освобождения блокировки синхронизации потока.
В Win32 реализующий эту идею неуправляемый класс C++ будет выглядеть примерно так:
class SomeType
{
private:
// Закрытое поле CRITICAL_SECTION, связанное с объектом.
CRITICAL_SECTION m_csObject;
public:
SomeType()
{
// Конструктор инициализирует поле CRITICAL_SECTION объекта.
InitializeCriticalSection(&m_csObject);
}
~SomeType()
{
// Деструктор удаляет поле CRITICAL_SECTION объекта.
DeleteCriticalSection(&m_csObject);
}
void SomeMethod()
{
// Мы используем поле CRITICAL_SECTION объекта для синхронизации
// доступа к объекту нескольких потоков.
EnterCriticalSection(&m_csObject);
// Здесь располагается код, исполняемый безопасно в отношении потоков.
LeaveCriticalSection(&m_csObject);
}
void AnotherMethod()
{
// Мы используем поле CRITICAL_SECTION объекта для синхронизации
// доступа к объекту нескольких потоков.
EnterCriticalSection(&m_csObject);
// Здесь располагается исполняемый безопасный код...
LeaveCriticalSection(&m_csObject);
}
};
В сущности, CLR предоставляет для каждого объекта отдельное поле по типу поля CRITICAL_SECTION и берет на себя задачи инициализации и удаления этого поля. Все, что остается сделать разработчику, — написать код для ввода поля в каждом методе, которому требуется синхронизация потоков.
Реализация «отличной» идеи
Сопоставление поля CRITICAL_SECTION (которое занимает примерно 24 байта в 32-разрядных системах и около 40 байт в 64-разрядных) с каждым объектом в куче довольно расточительно, особенно если для большинства объектов никогда не требуется безопасный доступ. Чтобы снизить расходование памяти, команда разработчиков CLR использует более эффективный способ предоставления только что описанной функциональности. Вот как это работает: при инициализации CLR выделяется память под массив блоков синхронизации. Блок синхронизации — это участок памяти, который можно связать с объектом. Каждый блок синхронизации содержит те же поля, что и Win32-структура CRITICAL_SECTION.
При создании объекта в куче, с ним связываются два дополнительных служебных поля. Первое служебное поле, указатель на объект-тип, содержит адрес памяти, по которому находится объект-тип типа. Второе служебное поле, индекс блока синхронизации, содержит целочисленный индекс блока в массиве блоков синхронизации.
При конструировании объекта индекс блока синхронизации получает отрицательное значение, указывающее, что нет блока синхронизации, поставленного в соответствие объекту. Затем, когда вызывается метод для входа в блок синхронизации объекта, CLR находит в массиве свободный блок синхронизации и задает индексу блока синхронизации объекта значение, соответствующее найденному блоку. Иначе говоря, блоки синхронизации связываются с объектами прямо во время выполнения. После того как все потоки освобождают блок синхронизации объекта, индекс блока синхронизации опять получает отрицательное значение, чтобы считаться свободным, и может связываться с другим объектом. На рис. 24-1 этот процесс показан наглядно.
Логически у каждого объекта в куче есть связанный с ним блок синхронизации, который можно использовать для быстрой синхронизации потоков. Однако физически структуры блоков синхронизации связываются с объектом только по необходимости, а когда эта необходимость отпадает, привязка снимается. Это обеспечивает эффективность использования памяти. Кстати, при необходимости в массиве блоков синхронизации могут создаваться дополнительные блоки, поэтому не стоит беспокоиться, что системе может не хватить блоков, если потребуется синхронизировать много объектов.
Рис. 24-1. Индекс блока синхронизации объектов в куче (включая объекты типов) может ссылаться на запись в массиве блоков синхронизации CLR