Опубликован: 25.03.2010 | Доступ: свободный | Студентов: 1447 / 158 | Оценка: 4.31 / 4.00 | Длительность: 25:42:00
Лекция 11:

Процессы, домены, потоки в C#

Потоки

Процесс, и домены внутри процесса, создают для исполняемого приложения комфортную среду обитания. Они изолируют код и данные от других исполняемых программ и предоставляют им необходимые сервисы. Но Windows является многозадачной операционной системой и должна выполнять все загруженные в нее задачи. Поэтому, имея в наличии только один процессор, она вынуждена эмулировать многозадачность выделением каждой задаче небольшого кванта времени, создавая иллюзию их одновременного выполнения. Такое поведение вполне приемлемо, потому что многие процессы представляют диалоговые приложения и в большинстве случаев находятся в состоянии простоя, ожидая ( idle ) действий пользователя.

Не все части процесса, ожидающего действий пользователя, могут простаивать одновременно. Некоторые части исполняемого приложения должны продолжать взаимодействовать с пользователем, ожидая его указаний, а другие в это время - исполнять уже полученные указания. Для реализации такого подхода код процесса разбивают на несколько завершенных частей, способных выполняться самостоятельно, и эти части называются потоками ( thread ). Таким образом, поток, это часть кода процесса, который способен реально выполняться процессором в данный момент.

Поток есть ничто иное, как контейнер для контролируемого исполнения какой-то функции. Когда функции выполняются только в одном потоке, работой каждой из них можно управлять только изнутри. Другое дело, когда функция выполняется в отдельном потоке-контейнере. В этом случае работой функции мы можем управлять из создавшего поток внешнего кода. Например, мы можем приостановить выполнение функции, назначить ей приоритет по отношению к функциям других потоков, перевести в фоновый режим работы или вообще прервать ее выполнение.

Процесс по отношению к потокам является контейнером, предоставляет им закрытое адресное пространство и следит за соблюдением политики операционной системы. Но реальный код приложения исполняют потоки. Все они имеют доступ к общей памяти приложения, выделенной им процессом. Но каждый из потоков имеет еще и свою локальную память TLS ( Thread Local Storage ), к которой имеет доступ только он сам.

Различают управляемые и неуправляемые потоки. Управляемые потоки создаются и действуют под контролем среды CRL, а неуправляемые - под контролем самой операционной системы. Любой поток, управляемый или неуправляемый, представлен экземпляром класса System.Threading.Thread.Оперируя сервисами этого класса мы можем контролировать работу потоков. Ниже приведены некоторые из этих сервисов.

Таблица 11.1 . Сервисы класса Thread для управления потоками
Член Пояснения
Thread() Конструктор с перегрузками для создания потока
Abort() Уничтожение потока
Suspend() Приостановление работы потока на неопределенное время
Sleep() Приостановление работы потока на заданное время
Join() Ожидание завершения работы потока
CurrentThread Свойство для извлечения текущего работающего потока
CurrentThread.Name Имя текущего потока
Priority Свойство для получения или изменения приоритета потока
Name Свойство для получения или изменения имени потока
IsBackground Булево свойство для подтверждения работы потока в фоновом режиме
ApartmentState Свойство, позволяющее получить или изменить тип COM -апартамента для данного потока
CurrentContext Статическое свойство чтения текущего контекста взаимодействия для данного потока
CurrentCulture Свойство для изменения региональных установок текущего потока
CurrentPrincipal Статическое свойство, управляющее защитой текущего потока на основе модели ролей
CurrentUICulture Свойство, представляющее собой идентификатор для менеджера ресурсов, управляющего региональными установками пользовательского интерфейса, представленного текущим потоком
IsAlive Булево свойство только для чтения, позволяющее определить, исполняется ли в данный момент поток
IsThreadPoolThread Булево свойство только для чтения, позволяющее определить, поступил ли данный поток из пула (накопительного буфера) потоков
ThreadState Свойство только для чтения, позволяющее определить состояние текущего потока
AllocateDataSlot() Статический метод, который резервирует неименованный слот в общей памяти всех потоков
AllocateNamedDataSlot() Статический метод, который резервирует именованный слот (участок памяти) в общей памяти всех потоков
FreeNamedDataSlot() Статический метод, который освобождает именованный слот в общей памяти всех потоков
GetDomain() Статический метод, возвращающий текущий домен, в котором исполняется данный поток
GetDomainID() Статический метод, возвращающий целое число, которое представляет собой идентификатор домена с исполняемым текущим потоком
SetData() Статический метод, записывающий данные в указанный слот персональной памяти TLS текущего исполняемого потока
GetNamedDataSlot() Статический метод, возвращающий данные именованного слота для текущего потока из его персональной памяти TLS
Interrupt() Прерывает исполнение потока
ResetAbort() Отменяет запрос на уничтожение потока, инициированный методом Abort(), после чего поток начинает выполняться с самого начала
Resume() Возобновляет работу ранее приостановленного потока
Start() Запускает поток на исполнение

Помещение в поток одной функции

Для любого приложения, запущенного на исполнение и загруженного в процесс, автоматически создается хотя бы один поток, который называется основным. Далее сама программа может создавать для отдельных своих частей дополнительные потоки и управлять ими. Этими частями являются методы, содержащие исполнимый код. Рассмотрим создание дополнительного потока и помещения в него одной функции на примере.

using System;
using System.Threading;
    
namespace Test
{
    class MyClass
    {
        // Закрытые поля с маркерами потоков
        int markerBaseThread, markerNewThread;
    
        // Открытые поля с идентификаторами доменов
        public int domainBaseThread, domainNewThread;
    
        // Свойства доступа закрытых полей (только для чтения)
        public int MarkerBaseThread
        {
            get { return markerBaseThread; }
        }
        public int MarkerNewThread
        {
            get { return markerNewThread; }
        }
    
        // Конструктор исполняется в основном потоке
        public MyClass()
        {
            // Извлечем маркер текущего потока
            markerBaseThread = Thread.CurrentThread.GetHashCode();
    
            // Извлекаем идентификатор домена
            domainBaseThread = Thread.GetDomainID();
    
            // Создаем специальный делегат со ссылкой на функцию
            // Создаем новый поток и присоединяем к нему исполняемый код
            // Запускаем код функции в новом потоке из текущего потока
            ThreadStart del = new ThreadStart(Func);    // Объект-делегат
            Thread th = new Thread(del);                // Новый поток
            th.Start();                                 // Выполнить функцию
        }
    
        // Метод будет исполняться в дополнительном потоке
        private void Func()
        {
            // Извлекаем маркер текущего потока
            markerNewThread = Thread.CurrentThread.GetHashCode();
    
            // Извлекаем идентификатор домена
            domainNewThread = Thread.GetDomainID();
        }
    }
    
    // Класс с точкой входа
    class Program
    {
        // Исполняется в основном потоке
        static void Main()
        {
            // Настройка консоли
            Console.Title = "Выполнение кода в 
		дополнительном потоке";
            Console.ForegroundColor = ConsoleColor.White;
            Console.CursorVisible = false;
            Console.WindowWidth = 57;
            Console.WindowHeight = 4;
    
            MyClass obj = new MyClass();// Исполняем
    
            // Показываем маркеры
            Console.WriteLine("Поток выполнения 
		конструктора MyClass(): {0} (в домене {1})",
                obj.MarkerBaseThread, obj.domainBaseThread);
            Console.WriteLine("Поток выполнения метода 
		Func(): {0} (в домене {1})",
                obj.MarkerNewThread, obj.domainNewThread);
            Console.WriteLine("Поток выполнения метода 
		Main(): {0} (в домене {1})",
                Thread.CurrentThread.GetHashCode(), Thread.GetDomainID());
    
            Console.ReadLine(); // Ждем нажатия клавиши Enter
        }
    }
}
Листинг 11.4 . Выполнение кода одной функции в дополнительном потоке

Результат показывает, что в одном домене выполняются два разных потока.

Максим Филатов
Максим Филатов

Прошел курс. Получил код Dreamspark. Ввожу код на сайте, пишет:

Срок действия этого кода проверки уже истек. Проверьте, правильно ли введен код. У вас осталось две попытки. Вы также можете выбрать другой способ проверки или предоставить соответствующие документы, подтверждающие ваш академический статус.

 

Как активировать код?