Российский Государственный Технологический Университет им. К.Э. Циолковского
Опубликован: 02.03.2007 | Доступ: свободный | Студентов: 5636 / 790 | Оценка: 3.96 / 3.45 | Длительность: 27:04:00
ISBN: 978-5-9556-0086-4
Лекция 15:

Потоки

А кто в домене живет?

Прилагаемый пример демонстрирует методы анализа процесса, домена и потоков (в .NET потоки и сборки также представлены объектами соответствующих классов).

Здесь показаны потоки в процессе, а также сборки, которые выполняются в домене приложения:

using System;
 using System.Windows.Forms;

 // Это пространство имен требуется для работы с классом Assembly.
 using System.Reflection;
 // Это пространство имен требуется для работы с классом Process.
 using System.Diagnostics;
namespace AppDomain1
 {
 class MyAppDomain
 {
 public static void ShowThreads()
 {
 Process proc = Process.GetCurrentProcess();
 foreach(ProcessThread aPhysicalThread in proc.Threads)
 {
 Console.WriteLine
  (aPhysicalThread.Id.ToString() + ":" + aPhysicalThread.ThreadState);
 }
 }

public static void ShowAssemblies()
 {
 // Получили ссылку на домен.
 AppDomain ad = AppDomain.CurrentDomain;
 // В рамках домена может быть множество сборок.
 // Можно получить список сборок домена.
 Assembly[] loadedAssemblies = ad.GetAssemblies();
 // У домена имеется FriendlyName, которое ему присваивается
 // при создании. При этом у него даже нет доступного конструктора.
 Console.WriteLine("Assemblies in {0} domain:", ad.FriendlyName);
 foreach(Assembly assembly in loadedAssemblies)
 {
 Console.WriteLine(assembly.FullName);
 }
 }
 	
static void Main(string[] args)
 {
 Console.WriteLine("=========================");
 // MessageBox.Show("XXX"); – Это всего лишь вызов метода класса 
 // MessageBox. Вызов выполняется лишь потому, что в домен с самого 
 // начала загружается сборка System.Windows.Forms.dll.
 MessageBox.Show("XXX");
 ShowThreads();
 ShowAssemblies();
 Console.WriteLine("=========================");
 // Даже в таком простом приложении в рамках домена приложения
 // живут три сборки! 
 }
 }
 }
Листинг 15.1.

Обзор пространства имен System.Threading

В этом пространстве объявляются типы, которые используются для создания многопоточных приложений: работа с потоком, средства синхронизации доступа к общим данным, примитивный вариант класса Timer... Много всего!

Тип Назначение
Interlocked Синхронизация доступа к общим данным
Monitor Синхронизация потоковых объектов при помощи блокировок и управления ожиданием
Mutex Синхронизация ПРОЦЕССОВ
Thread Собственно класс потока, работающего в среде выполнения .NET. В текущем домене приложения с помощью этого класса создаются новые потоки
ThreadPool Класс, предоставляющий средства управления набором взаимосвязанных потоков
ThreadStart Класс-делегат для метода, который должен быть выполнен перед запуском потока
Timer Вариант класса-делегата, который обеспечивает передачу управления некоторой функции-члену (неважно какого класса!) в указанное время. Сама процедура ожидания выполняется потоком в пуле потоков
TimerCallback Класс-делегат для объектов класса Timer.
WaitHandle Объекты – представители этого класса являются объектами синхронизации (обеспечивают многократное ожидание).
WaitCallback Делегат, представляющий методы для рабочих элементов (объектов) класса ThreadPool

Класс Thread. Общая характеристика

Thread -класс представляет управляемые потоки: создает потоки и управляет ими — устанавливает приоритет и статус потоков. Это объектная оболочка вокруг определенного этапа выполнения программы внутри домена приложения.

Статические члены класса Thread Назначение
CurrentThread Свойство. Только для чтения. Возвращает ссылку на поток, выполняемый в настоящее время
GetData() SetData() Обслуживание слота текущего потока
GetDomain() GetDomainID() Получение ссылки на домен приложения (на ID домена), в рамках которого работает указанный поток
Sleep() Блокировка выполнения потока на определенное время
Нестатические члены Назначение
IsAlive Свойство. Если поток запущен, то true
IsBackground Свойство. Работа в фоновом режиме. GC работает как фоновый поток
Name Свойство. Дружественное текстовое имя потока. Если поток никак не назван – значение свойства установлено в null. Поток может быть поименован единожды. Попытка переименования потока возбуждает исключение
Priority Свойство. Значение приоритета потока. Область значений – значения перечисления ThreadPriority
ThreadState Свойство. Состояние потока. Область значений – значения перечисления ThreadState
Interrupt() Прерывание работы текущего потока
Join() Ожидание появления другого потока (или определенного промежутка времени) с последующим завершением
Resume() Возобновление выполнения потока после приостановки
Start() Начало выполнения ранее созданного потока, представленного делегатом класса ThreadStart
Suspend() Приостановка выполнения потока
Abort() Завершение выполнения потока посредством генерации исключения TreadAbortException в останавливаемом потоке. Это исключение следует перехватывать для продолжения выполнения оставшихся потоков приложения. Перегруженный вариант метода содержит параметр типа object, который может включать дополнительную специфичную для данного приложения информацию.

Именование потока

Потоки рождаются безымянными. Это означает, что у объекта, представляющего поток, свойство Name имеет значение null. Ничего страшного. Главный поток все равно изначально поименовать некому. То же самое и с остальными потоками. Однако никто не может помешать потоку поинтересоваться своим именем — и получить имя. Несмотря на то, что это свойство при выполнении приложения играет вспомогательную роль, повторное переименование потоков недопустимо. Повторное изменение значения свойства Name приводит к возбуждению исключения.

using System;
 using System.Threading;

namespace ThreadApp_1
 {
 class StartClass
 {
 static void Main(string[] args)
 {//==============================================================
 int i = 0;
 bool isNamed = false;
 do 
 {

try
 {
 if (Thread.CurrentThread.Name == null) 
 {
 Console.Write("Get the name for current Thread > ");
 Thread.CurrentThread.Name = Console.ReadLine();
 }
 else
 {
 Console.WriteLine("Current Thread : {0}.", Thread.CurrentThread.Name);	
if (!isNamed)
 {
 Console.Write("Rename it. Please...");
 Thread.CurrentThread.Name = Console.ReadLine();
 }
 }
 }
 catch (InvalidOperationException e)
 {
 Console.WriteLine("{0}:{1}",e,e.Message);
 isNamed = true;
 }

i++;
 }
 while (i < 10);

 }//=============================================================
 }
 }
Листинг 15.2.

Игры с потоками

Но сначала о том, что должно происходить в потоке. Выполнение текущего потока предполагает выполнение программного кода.

Что это за код? Это код приложения. Это код статических и нестатических методов – членов классов, которые объявляются или просто используются в приложении.

Запустить поток можно единственным способом: указав точку входа потока – метод, к выполнению операторов которого должен приступить запускаемый поток.

Точкой входа ПЕРВИЧНОГО потока являются СТАТИЧЕСКИЕ функции Main или WinMain. Точнее, первый оператор метода.

Точка входа ВТОРИЧНОГО потока назначается при создании потока.

А дальше – как получится. Поток выполняется оператор за оператором. Со всеми циклами, заходами в вызываемые функции, в блоки свойств, в операторы конструкторов... И так продолжается до тех пор, пока:

  • не возникнет неперехваченное исключение;
  • не будет достигнут конец цепочки операторов (последний оператор в функциях Main или WinMain );
  • не будет отработан вызов функции, обеспечивающей прекращение выполнения потока.

Поскольку первичный поток создается и запускается автоматически (без какого-либо особого участия со стороны программиста), то и заботиться в случае простого однопоточного приложения не о чем.

При создании многопоточного приложения забота о создании дополнительных потоков – это забота программиста. Здесь все надо делать своими руками.

Деятельность по созданию потока предполагает три этапа:

  • определение метода, который будет играть роль точки входа в поток;
  • создание объекта – представителя специального класса-делегата ( ThreadStart class ), который настраивается на точку входа в поток;
  • создание объекта – представителя класса потока. При создании объекта потока конструктору потока передается в качестве параметра ссылка на делегата, настроенного на точку входа.

Замечание. Точкой входа в поток не может быть конструктор, поскольку не существует делегатов, которые могли бы настраиваться на конструкторы.

kewezok kewezok
kewezok kewezok
Елена Шляхт
Елена Шляхт
Объясните плиз в чем отличие а++ от ++а
Почему результат разный?
int a=0, b=0;
Console.WriteLine(a++); //0
Console.WriteLine(++b); //1
a++;
++b;
Console.WriteLine(a); //2
Console.WriteLine(b); //2