- •1. Язык программирования c# 3
- •2. Базовые элементы .Net Framework 67
- •3. ТЕхнология .Net Remoting 144
- •Введение
- •1. Язык программирования c#
- •1.1. Платформа .Net – обзор архитектуры
- •1.2. Язык c# - общие концепции синтаксиса
- •1.3. Система типов языка c#
- •1.4. Преобразования типов
- •1.5. Идентификаторы, ключевые слова и литералы
- •1.6. Объявление переменных, полей и констант
- •1.7. Выражения и операции
- •1.8. Операторы языка c#
- •1.9. Объявление и вызов методов
- •1.10. Массивы в c#
- •1.11. Работа с символами и строками в c#
- •1.12. Синтаксис объявления класса, Поля и методы класса
- •1.13. Свойства и индексаторы
- •1.14. Конструкторы класса и Жизненный цикл объекта
- •1.15. Наследование классов
- •1.16. Перегрузка операЦий
- •1.17. Делегаты
- •1.18. События
- •1.19. Интерфейсы
- •1.20. Структуры и перечисления
- •1.21. Пространства имен
- •1.22. Генерация и обработка исключительных ситуаций
- •1.23. Нововведения в языке c# 2.0
- •1.24. Обобщенные типы (generics)
- •2. Базовые элементы .Net Framework
- •2.1. Метаданные и механизм отражения
- •2.2. Пользовательские и встроенные атрибуты
- •2.3. Пространство имен system.Collections
- •2.4. Работа с файлами и директориями
- •2.5. Использование потоков данных
- •2.6. Сериализация
- •2.7. Сериализация объектов в нестандартном формате
- •2.8. Введение в xml
- •2.9. Работа с xml-документами в .Net framework
- •2.10. МНогопоточное программирование
- •2.11. Синхронизация потоков
- •2.12. Асинхронный вызов методов
- •2.13. Состав и взаимодействие сборок
- •2.14. Конфигурирование сборок
- •3. ТЕхнология .Net Remoting
- •3.1. Домены приложений
- •3.2. Архитектура .Net Remoting
- •3.3. Активация удаленных объектов и их время жизни
- •3.4. Программная настройка Remoting
- •3.5. Удаленные Объекты с клиентской активацией
- •3.6. Настройка Remoting при помощи конфигурационных файлов
- •3.7. Хостинг распределенных приложений
- •3.8. Объекты-сообщения
- •3.9. Пользовательские канальные приемники
- •4.1. Архитектура ado.Net
- •4.2. Учебная база cd Rent
- •4.3. Соединение с базой данных
- •4.4. Выполнение команд и запросов к базе данных
- •4.5. Чтение данных и объект DataReader
- •4.6. Параметризированные запросы
- •4.7. Рассоединенный набор данных
- •4.8. Заполнение Рассоединенного набора данных
- •4.9. Объект класса DataColumn – колонка таблицы
- •4.10. Объекты класса DataRow – строки таблицы
- •4.11. Работа с объектом класса DataTable
- •4.12. DataSet и схема рассоединенного набора данных
- •4.13. Типизированные DataSet
- •4.14. Поиск и фильтрация данных в DataSet
- •4.15. Класс DataView
- •4.16. СиНхронизация набора данных и базы
- •5.1. Архитектура и общие концепции asp.Net
- •5.2. Пример aspx-страницы. Структура страницы
- •5.3. Директивы страницы
- •5.4. Класс System.Web.Ui.Page. События страницы
- •5.5. Серверные элементы управления
- •5.6. Элементы управления Web Controls
- •5.7. Проверочные элементы управления
- •5.8. Списковые элементы управления
- •5.9. Связывание данных
- •5.11. Управление состояниями в web-приложениях
- •5.12. Кэширование
- •5.13. Безопасность в web-приложениях
- •5.14. Создание пользовательских элементов управления
- •Литература
2.10. МНогопоточное программирование
Классы, предназначенные для поддержки многопоточного программирования, сосредоточены в пространстве имен System.Threading. В среде .NET каждый поток представлен объектом класса System.Threading.Thread. Для организации собственного потока необходимо создать объект указанного класса. Класс Thread имеет единственный конструктор:
public Thread(ThreadStart start);
В качестве параметра конструктор принимает делегат типа ThreadStart, который должен ссылаться на пользовательский метод, выполняемый в потоке.
public delegate void ThreadStart();
Следует учесть, что создание потока не подразумевает его автоматического запуска. Для запуска потока требуется вызвать у объекта метод Start().
Продемонстрируем создание и запуск потоков на простейшем примере. Программа содержит два потока, каждый из которых в бесконечном цикле выводит данные на консоль:
using System;
using System.Threading; //Необходимо для работы с потоками
class MainClass {
// Эта функция будет выполняться в отдельном потоке
public static void DoSomeWork() {
while (true) {
Console.WriteLine("The second thread");
// Создаем видимость работы
for (int i = 0; i < 1000000; i++){ i++; }
}
}
public static void Main() {
// Создали объект потока
Thread th = new Thread(new ThreadStart(DoSomeWork));
// Запустили поток
th.Start();
// Создаем видимость работы
while (true) {
Console.WriteLine("The first thread");
for (int i = 0; i < 1000000; i++){ i++; }
}
}
}
Рассмотрим работу с членами класса Thread подробнее. Любой поток характеризуется приоритетом выполнения, который влияет на количество квантов процессорного времени, выделяемых потоку. Для работы с приоритетами класс Thread содержит свойство Priority, доступное для чтения и записи. Значением свойства являются элементы перечисления ThreadPriority: Lowest, BelowNormal, Normal, AboveNormal, Highest:
// Создали объект потока
Thread th = new Thread(new ThreadStart(DoSomeWork));
// Назначим потоку низкий приоритет
th.Priority = ThreadPriority.Lowest;
// Запустим поток
th.Start();
Среда исполнения платформы .NET разделяет все потоки на фоновые и основные. Главное приложение не может завершиться, пока не завершены все его основные потоки. Если работа приложения завершается, а некоторые фоновые потоки еще работают, то их работа автоматически прекращается. Таким образом, к основным следует относить такие потоки, которые выполняют критические для приложения действия. Для установки типа потока следует использовать свойство IsBackground булевого типа. Следующий пример показывает применение свойства:
using System;
using System.Threading;
class MainClass {
public static void DoSomeWork() {
while (true) {
Console.WriteLine("The second thread");
// Этот метод приостанавливает поток на 400 мсек
Thread.Sleep(400);
}
}
public static void Main() {
Thread th = new Thread(new ThreadStart(DoSomeWork));
th.IsBackground = true; // Поток будет фоновым
th.Start();
// "Усыпили" основной поток на 2 секунды
Thread.Sleep(2000);
Console.WriteLine("Quit from main thread");
}
}
По умолчанию любой поток создается как основной, поэтому, если закомментировать строку th.IsBackground = true и запустить приложение, то самостоятельно закончить работу оно не сможет.
Класс Thread предоставляет встроенные механизмы управления потоками. Метод Suspend() вызывает приостановку потока, метод Resume() возобновляет работу потока. Статический метод Sleep() приостанавливает выполнение того потока, в котором вызывается, на указанное количество миллисекунд:
// Пусть объект th связан с некоторым потоком
th.Suspend(); // Приостановили поток
th.Resume(); // Запустили снова
Thread.Sleep(2000); // "Усыпили" поток на 2 секунды
Для приостановки работы произвольного потока на заданное время может использоваться такой код (штатных методов для этого не существует):
th.Suspend();
Thread.Sleep(2000);
th.Resume();
Если вызвать метод Sleep() с параметром -1, то поток будет остановлен навсегда.
Метод Join() позволяет дождаться завершения работы того потока, у которого вызывается. Модификация данного метода блокирует выполнение текущего потока на указанное количество миллисекунд:
Thread th = new Thread(new ThreadStart(DoSomeWork));
th.Start(); // Создали и запустили поток
th.Join(); // Ждем, пока этот поток отработает
. . .
Thread th = new Thread(new ThreadStart(DoSomeWork));
th.Start(); // Создали и запустили поток
// Будем ждать 1 секунду. Если за это время поток th
// завершиться, то значение res будет true
bool res = th.Join(1000);
Для завершения работы выбранного потока используется метод Abort(). Данный метод генерирует специальное исключение ThreadAbortException. Особенность этого исключения состоит в том, что его невозможно подавить при помощи catch-блока. Исключение может быть отслежено (в частности, тем потоком, который кто-то собирается уничтожить), а при помощи статического метода ResetAbort() запрос на уничтожение потока можно отклонить.
using System;
using System.Threading;
class MainClass {
public static void ThreadProc() {
while(true)
try {
Console.WriteLine("Some work...");
Thread.Sleep(1000);
} catch (ThreadAbortException e) {
// Отлавливаем попытку уничтожения и отменяем ее
Console.WriteLine("Somebody tries to kill me!");
Thread.ResetAbort();
}
}
public static void Main() {
// Создаем и запускаем поток
Thread th = new Thread(new ThreadStart(ThreadProc));
th.Start();
// Подождем 10 секунд
Thread.Sleep(10000);
// Пытаемся прервать работу потока
th.Abort();
// Дождемся завершения потока. Вернее, никогда мы его
// не дождемся, так как поток сам себя "воскресил"
th.Join();
}
}
Информацию о текущем состоянии потока можно получить посредством свойства ThreadState, значением которого являются элементы перечисления ThreadState. Свойство IsAlive позволяет определить, исполняется ли в данный момент поток. Статическое свойство CurrentThread возвращает объект, представляющий текущий поток. Свойство Name служит для установки или чтения строки с именем потока.
Рассмотрим один вспомогательный класс из пространства System.Threading – класс Timer. При помощи этого класса можно организовать вызов определенного метода через указанный промежуток времени.
using System;
using System.Threading;
class MyApp {
static bool TickNext = true;
static void Main() {
Console.WriteLine("Press Enter to terminate...");
TimerCallback callback = new TimerCallback(TickTock);
Timer timer = new Timer(callback, null, 1000, 2000);
Console.ReadLine();
}
static void TickTock(object state) {
Console.WriteLine(TickNext ? "Tick" : "Tock");
TickNext = ! TickNext;
}
}
В приведенном примере через 1 секунду после создания (третий параметр в конструкторе Timer) с периодичностью 2 секунды (четвертый параметр конструктора) вызывается метод, заданный делегатом callback (первый параметр конструктора и инициализация делегата). Более подробное описание класса Timer можно найти в соответствующем разделе документации SDK.