
- •Организация c#-системы ввода-вывода: байтовые и символьные потоки. Встроенные потоки.
- •Классы потоков. Класс Stream. Классы байтовых потоков. Классы символьных потоков. Классы двоичных потоков.
- •Класс FileStream и файловый ввод-вывод на побайтовой основе. Открытие и закрытие файла. Запись данных в файл. Считывание байтов из объекта класса FileStream.
- •Файловый ввод-вывод с ориентацией на символы. Использование класса StreamWriter. Использование класса StreamReader.
- •Считывание и запись двоичных данных. Класс BinaryWriter. Класс BinaryReader.
- •6. Навигация по файловой системе: классы для работы с файловой системой.
- •7. Получение сведений о файле; копирование файлов; перечисление файлов в папке; изменение расширения файлов.
- •5.3. Изменение расширения файлов
- •8. Основы организации потоков. Потоки и многозадачность. Пространство имен System.Threading. Класс Thread. Создание потока.
- •9. Использование нескольких потоков. Планирование потоков, приоритеты потоков.
- •10. Проблемы одновременности и синхронизации потоков. Общий доступ к данным из разных потоков, предотвращение коллизий.
- •11. Синхронизация доступа к общим данным с помощью блокировок. Управление временем существования потоков.
- •12. Краткий обзор ado.Net. Три стороны технологии ado.Net. Пространство имен System.Data.
- •13. Поставщики данных ado.Net. Поведение объектов подключения.
- •14. Объектная модель ado.Net
- •16. Создание соединения с источником данных. Члены типа dbConnection. Обработка исключений при работе с ms sql
- •Конструкторы
- •Свойства
- •События
- •17. Работа с бд с пом. Sql-запросов. Класс SqlCommand. Объект Command. Создание и инициализация. Командная строка sql-запроса CommandText.
- •Конструкторы
- •Свойства
- •18. Выборка, добавление, удаление и обновление данных с помощью sql-запросов на подсоединенном уровне.
- •19. Вывод информации с использованием объекта чтения данных: создание SqlDataReader; чтение данных из DataReader; чтение полей из текущей записи; закрытие DataReader.
- •20. Организация хранения данных. Объект DataSet
- •21. Таблицы и поля: объекты DataTable и DataColumn
- •22. Строки: объект DataRow
- •23. Связи между таблицами: объект DataRelation
- •24. Создание подключения к базе данных. Управляемые провайдеры
- •25. Объект DataAdapter. Класс SqlDataAdapter
- •Конструкторы:
- •Свойства
- •Организация c#-системы ввода-вывода: байтовые и символьные потоки. Встроенные потоки.
10. Проблемы одновременности и синхронизации потоков. Общий доступ к данным из разных потоков, предотвращение коллизий.
При программировании для однопоточного окружения методы зачастую пишутся так, что на некоторых этапах исполнения кода объекты временно находятся в недействительном состоянии. Очевидно, что если в любой момент к объекту обращается только один поток, у вас есть гарантия, что каждый метод завершится до того, как будет вызван следующий метод. Это значит, что для своих клиентов объект всегда пребывает в действительном состоянии. Однако когда несколько потоков работают одновременно, вы легко можете получить ситуации, в которых процессор переключается на другой поток, в то время как ваш объект находится в недействительном состоянии. Если затем этот поток также попытается использовать этот же объект, результат будет совершенно непредсказуем. Поэтому термин "безопасность потоков" означает постоянное поддержание членов объекта в действительном состоянии при их одновременном использовании несколькими потоками.
Как избежать подобных непредсказуемых состояний? Для этого можно использовать стандартное средство — синхронизация. Синхронизация позволяет задавать критические секции (critical sections) кода, в которые в каждый отдельный момент может входить только один поток, гарантируя, что любые временные недействительные состояния объекта будут невидимы его клиентам. Имеется несколько средств определения критических секций, включая классы .NET Monitor и Mutex, а также оператор С# lock.
Формат использования инструкции lock таков:
lock(выражение) {
// Инструкции, подлежащие синхронизации.
}
Для обычных методов в качестве выражения используется указатель this, для статических – typeof(класс).
Здесь параметр выражение представляет собой ссылку на синхронизируемый объект. Если нужно синхронизировать только один элемент, фигурные скобки можно опустить. Инструкция lock гарантирует, что указанный блок кода, защищенный блокировкой для данного объекта, может быть использован только потоком, который получает эту блокировку. Все другие потоки остаются заблокированными до тех пор, пока блокировка не будет снята. А снята она будет лишь при выходе из этого блока.
Итак, подытожим действие инструкции lock.
1. Если для заданного объекта инструкция lock размещена в некотором блоке кода, этот объект блокируется, и никакой другой поток не сможет запросить блокировку.
2. Другие потоки, пытающиеся запросить блокировку для того же объекта, перейдут в состояние ожидания и будут находиться в нем до тех пор, пока код не будет разблокирован.
3. Объект разблокируется, когда поток выходит из заблокированного блока.
Необходимо также отметить, что инструкция lock должна использоваться только для объектов, которые определены либо как private-, либо как internal-объекты. В противном случае внешние по отношению к вашей программе потоки смогут получать блокировку и не снимать ее.
11. Синхронизация доступа к общим данным с помощью блокировок. Управление временем существования потоков.
Иногда выполнение потока необходимо приостановить. Например, поток можно использовать для отображения времени суток. Если пользователь желает убрать часы с экрана, соответствующий поток можно приостановить. Позже, когда необходимость в часах появится снова, выполнение приостановленного потока можно возобновить. В любом случае приостановить и возобновить поток — дело нехитрое. Иногда нужно и вовсе завершить выполнение потока. Завершение выполнения потока отличается от приостановки тем, что завершенный поток удаляется из системы, и его выполнение не может быть возобновлено в дальнейшем.
Часто приложение должно ожидать завершения выполнения потока. Для этого в классе Thread предусмотрен метод Join. Метод Join сообщает системе, что приложение должно ожидать завершения потока. Конечно, в таком простом примере второй поток на самом деле не нужен, так как система простаивает в ожидании его завершения. Для большей наглядности создадим пять потоков, выполняющих некоторые операции, и организуем ожидание их завершения. При работе с многопоточным кодом задача программиста несколько усложняется, так необходимо дождаться завершения всех потоков. Сделать это можно, сохранив ссылки на все потоки и вызвав для каждого из них метод Join, чтобы дождаться завершения очередного потока.
Для приостановки потока используйте метод Thread. Suspend(), а для его возобновления — метод Thread.Resume(). Форматы использования этих методов таковы:
public void Suspend()
public void Resume()
Если вызывающий поток находится не в подходящем для вызываемого метода состоянии, генерируется исключение типа ThreadStateException. Такие последствия может иметь, например, попытка возобновить поток, который не был приостановлен. Чтобы завершить поток, используйте метод Thread.Abort(). Самый простой формат его использования выглядит так:
public void Abort(). Метод Abort() генерирует исключение типа ThreadAbortException для потока, из которого этот метод вызван. Это исключение и заставляет поток завершиться. Кроме того, то же самое исключение может быть перехвачено программным кодом (с автоматической его регенерацией для завершения потока). Однако следует учитывать, что метод Abort() не всегда способен немедленно остановить выполнение потока, поэтому, если важно, чтобы поток был завершен до продолжения вашей программы, необходимо сопроводить вызов метода Abort() вызовом метода Join(). В некоторых (довольно редких) случаях метод Abort() не в состоянии завершить поток. Это возможно в ситуации, когда finally-блок включен в бесконечный цикл.