- •Сборки (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. Создание и использование итераторов.
- •Общие сведения о итераторах
К вопросу об эффективном использовании потоков
По собственном опыту знаю, что разработчики слишком часто используют потоки в приложениях. Как показывает история, раньше операционные системы не поддерживали потоки. В однопоточных системах был лишь один поток, попеременно выполнявший все программы, а ошибка в программе приводила к сбою всей системы. Например, таковы 16-разрядные версии Windows: бесконечный цикл или сбой одного приложения «подвешивал» всю систему и заставлял принудительно перезагружаться. Поддержка многопоточности впервые была реализована в Windows NT 3.1 с целью повышения устойчивости системы. Каждому процессу выделялся отдельный поток, и зацикливание или зависание потока одного процесса не приводило к сбою потоков других процессов и всей системы.
Если быть точным, потоки приводят к издержкам. Создание потока обходится недешево: объект ядра процесса должен быть размещен и инициализирован, для каждого потока резервируется (и по требованию выделяется) 1 Мб адресного пространства для его стека пользовательского режима, и еще примерно 12 Кб выделяется для стека режима ядра.
Создав поток, Windows сразу же вызывает функцию в каждой DLL-библиотеке процесса, уведомляя все DLL-библиотеки о создании нового потока. Уничтожение потока также требует затрат: каждая DLL-библиотека в процессе получает уведомление об уничтожении потока, также следует очистить объект ядра и стеки.
На однопроцессорных компьютерах в каждый момент времени может выполняться всего один поток. Windows должна отслеживать объекты-потоки и время от времени решать, какой поток процессор будет обрабатывать следующим. А это дополнительный код, выполняющийся примерно раз в 20 мс. Остановку выполнения процессором кода одного потока и запуск на выполнение кода другого потока называют переключением контекста (context switch). Оно обходится недешево, поскольку ОС должна выполнить следующее.
Перейти в режим ядра.
Сохранить регистры процессора в объекте ядра текущего процесса. Между прочим, регистры процессора занимают примерно 700 байт в процессорных архитектурах х8б, 1240 байт — в хб4 и 2500 байт — в 1Аб4.
Установить спин-блокировку, определить, какой поток поставить следующим, и освободить спин-блокировку. Если следующий поток относится к другому процессу, затраты увеличатся, потому что потребуется переключение виртуального адресного пространства.
Загрузить регистры процессора со значениями из объекта ядра потока, который будет выполняться следующим.
Выйти из режима ядра.
Все это — чистые издержки, замедляющие работу Windows и всех приложений по сравнению с однопоточной системой. Но они необходимы, потому что Microsoft стремится к созданию отказоустойчивой ОС, не подверженной сбоям при неполадках в ходе выполнения кода приложений.
Все это аргументы в пользу следующего утверждения: потоки следует использовать как можно реже. Чем больше создается потоков, тем больше издержки в системе и тем медленнее работает приложение. Кроме того, каждому потоку нужны ресурсы (память для объекта ядра и двух стеков), кроме того, поток занимает память, которая становится недоступной для ОС и приложений. Помимо повышения отказоустойчивости, потоки служат еще одной полезной цели — масштабируемости.
В многопроцессорной системе Windows может планировать несколько потоков: по одному на каждый процессор. В таком случае имеет смысл создавать несколько потоков, чтобы эффективно задействовать возможности аппаратного обеспечения. Именно к этому все чаще прибегают разработчики. Мы привыкли, что с каждым годом процессоры становились все мощнее, а, значит, написанные тогда приложения работали быстрее на компьютерах с более мощным процессором. Но производителям процессоров, в числе которых Intel и AMD, становится все сложнее создавать более мощные процессоры, потому что современные процессорные архитектуры и аппаратные компоненты почти достигли пределов в рамках существующих конструкторских решений.
Современные технологии производства процессоров ограничены физическим размером процессоров, поэтому производители процессоров считают более эффективным создавать отдельные чипы, включающие несколько процессоров. Такие чипы повышают производительность многопоточных ОС и приложений за счет одновременного выполнения нескольких процессов. Современные производители процессорных чипов используют два типа технологий — Hyperthreading и многоядерную (multi-core), — которые позволяют представить для Windows и приложений отдельный чип как два (и более) процессора. На самом деле есть чипы, например, Intel Pentium Extreme), воплощающие обе технологии.
Так, для ОС Windows один процессор Pentium Extreme равнозначен четырем процессорам! В некоторых чипах, например Intel Xeon и Intel Pentium 4, реализована Нурег-:hreading. В этой технологии физический процессор состоит из двух логических. / каждого из них есть своя архитектура (регистры процессора), но они пользуется общими рабочими ресурсами, например кешем процессора. Когда один логический процессор приостанавливается (из-за промаха кеша, ошибочного прогнозирования ветви или ожидания результатов предыдущей команды), чип переключается на другой логический процессор. В идеале для процессоров, использующих Hyperthreading, можно рассчитывать на стопроцентное улучшение производительности, ведь теперь вместо одного процессора работают сразу два. Но, поскольку они используют общие рабочие ресурсы, ожидаемого резкого повышения производительности нет. Так, по сообщению Intel, производительность повышается всего на 10-30%.
В некоторых чипах, таких как Intel Pentium В и AMD Athlon 64 Х2, реализована технология нескольких ядер. На многоядерном чипе есть два физических процессора. У каждого — своя архитектура и рабочие ресурсы. Можно ожидать, что его рабочие характеристики будут лучше, чем у чипа Hyperthreading, и обеспечат стопроцентную производительность, потому что два процессора выполняют независимые задачи.
Итак, на сегодняшний день производители процессоров не могут создать более быстрые процессоры, поэтому они совмещают несколько более медленных. Поэтому для обеспечения быстрой работы приложений в будущем их следует создавать с расчетом на использование дополнительных процессоров. Для этого нужны несколько потоков, а потоки — это лишние издержки; они замедляют работу и расходуют ресурсы.