Всего различают две разновидности многозадачности: на основе процессов и на основе потоков. Отличия многозадачности на основе процессов и потоков сводится к следующему: многозадачность на основе процессов организуется для параллельного выполнения программ, а многозадачность на основе потоков - для параллельного выполнения отдельных частей одной программы. В .NET Framework поддерживаются обе разновидности многозадачности: на основе процессов и на основе потоков. Поэтому можно создавать как процессы, так и потоки, а также управлять и теми и другими.
Классы, поддерживающие многопоточное программирование, определены в пространстве имен System.Threading. Поэтому любая многопоточная программа включает в себя следующую строку кода (C#):
using System.Threading;
Пространство имен System.Threading содержит различные типы, позволяющие создавать многопоточные приложения. Одним из основных классов в данном пространстве имен является класс Thread.
Класс Thread является самым элементарным из всех типов пространства имен System.Threading. Основные свойства и методы класса Thread приведены в таблице ниже.
| Имя | Описание |
|---|---|
CurrentContext
|
Это свойство только для чтения возвращает контекст, в котором в данный момент выполняется поток |
CurrentThread |
Это свойство только для чтения возвращает ссылку на текущий выполняемый поток |
GetDomain(), GetDomainID()
|
Этот метод возвращает ссылку на текущий AppDomain или идентификатор этого домена, в котором выполняется текущий поток |
Sleep()
|
Этот метод приостанавливает текущий поток на заданное время |
IsAlive |
Возвращает булевское значение, указывающее на то, запущен ли поток (и еще не прерван и не отменен) |
IsBackground |
Получает или устанавливает значение, указывающее, является ли данный поток "фоновым" (подробнее объясняется далее) |
Name |
Позволяет вам установить дружественное текстовое имя потока |
Priority |
Получает или устанавливает приоритет потока, который может принимать значение из перечисления ThreadPriority |
ThreadState |
Получает состояние данного потока, которому может быть присвоено значение из перечисления ThreadState |
Abort() |
Инструктирует CLR прервать поток, как только это будет возможно |
Interrupt() |
Прерывает (т.е. приостанавливает) текущий поток на заданный период ожидания |
Join() |
Блокирует вызывающий поток до тех пор, пока указанный поток (тот, для которого вызван Join()) не завершится |
Resume() |
Возобновляет ранее приостановленный поток |
Start() |
Инструктирует CLR запустить поток как можно скорее |
Suspend() |
Приостанавливает поток. Если поток уже приостановлен, вызов Suspend() не дает эффекта |
При создании многопоточного приложения, необходимо, руководствоваться следующими шагами:
ParametrizedThreadStart (или ThreadStart), передав конструктору метод, который определен на предыдущем шаге.
ParametrizedThreadStart/ThreadStart.
Thread.Start(). Это действие запустит поток на методе, который указан делегатом, созданным на втором шаге, как только это будет возможно. Всего различают два типа потоков:
Thread.Start(), автоматически становится потоком переднего плана. Данный тип потоков обеспечивают предохранение текущего приложения от завершения. Среда CLR не остановит приложение до тех пор, пока не будут завершены все приоритетные потоки.
IsBackground значение true.Для того что бы присвоить потоку приоритет, нужно использовать свойство Priority в классе Thread, которое определяет, сколько времени на исполнение будет выделено потоку относительно других потоков того же процесса. Существует 5 градаций приоритета потока:
enum ThreadPriority { Lowest, BelowNormal, Normal, AboveNormal, Highest }
Значение приоритета становится существенным, когда одновременно исполняются несколько потоков. Установка приоритета потока на максимум еще не означает работу в реальном времени (real-time), так как существуют еще приоритет процесса приложения. Для того, чтобы поток работал в режиме реального времени (real-time), используется класс Process из пространства имен System.Diagnostics для поднятия приоритета:
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
От ProcessPriorityClass.High один шаг до наивысшего приоритета процесса - Realtime. При использовании процесса в режиме приоритета Realtime, то процесс никогда не вытиснится, и если программа случайно попадет в бесконечный цикл, операционная система может быть полностью заблокирована. Спасти вас в этом случае сможет только кнопка выключения питания или перезагрузки. По этой причине ProcessPriorityClass.High считается максимальным приоритетом процесса, рекомендованным к использованию.
Поток создается за счет вызова метода Start() объекта Thread. Однако после вызова метода Start() новый поток все еще пребывает в состоянии Unstarted. В состояние Running поток переходит сразу после того, как планировщик потоков операционной системы выберет его для выполнения. Информация о текущем состоянии потока доступна через свойство Thread.ThreadState.
С помощью метода Thread.Sleep() поток можно перевести в состояние WaitSleepJoin и при этом указать, через какой промежуток времени поток должен возобновить работу:
thread.Sleep(1000);
Для прерывания работы потока, используется метод Thread.Abort():
thread.Abort()
При вызове этого метода в соответствующем потоке генерируется исключение типа ThreadAbortException в том потоке, для которого он был вызван. Это исключение приводит к прерыванию потока и может быть перехвачено и в коде-программы, но в этом случае оно автоматически генерируется еще раз, чтобы остановить поток. Метод Abort() не всегда способен остановить поток немедленно, поэтому если поток требуется остановить перед тем, как продолжить выполнение программы, то после метода Abort() следует сразу же вызвать метод Join().Кроме того, в самых редких случаях методу Abort() вообще не удается остановить поток. Это происходит, например, в том случае, если кодовый блок finally входит в бесконечный цикл.
Запрос на преждевременное прерывание может быть переопределен в самом потоке. Для этого необходимо сначала перехватить в потоке исключение ThreadAbortException, а затем вызвать метод ResetAbort(). Благодаря этому исключается повторное генерирование исключения по завершении обработчика исключения, прерывающего данный поток. Ниже приведена форма объявления метода ResetAbort():
Thread.ResetAbort();
Вызов метода ResetAbort() может завершиться неудачно, если в потоке отсутствует надлежащий режим надежной отмены преждевременного прерывания потока.
При использовании различных коротких задач, подлежащие выполнению, можно заранее создать набор потоков и затем просто отправлять соответствующие запросы, когда наступает очередь для их выполнения, т.е. если количество этих потоков автоматически увеличивалось с ростом необходимости в этих потоках и уменьшалось при возникновении потребности в освобождении ресурсов.
Для управления списком потоков предусмотрен класс ThreadPool, который по мере необходимости уменьшает и увеличивает количество потоков в пуле до максимально допустимого значения. Значение максимально допустимого количества потоков в пуле может изменяться. В случае двуядерного ЦП оно по умолчанию составляет 1023 рабочих потоков и 1000 потоков ввода-вывода.
Для того, чтобы запросить поток из пула для обработки вызова метода, можно использовать метод QueueUserWorkItem(). Этот метод перегружен, чтобы в дополнение к экземпляру делегата WaitCallback позволить указывать необязательный параметр System.Object для специальных данных состояния.
Ниже приведен пример приложения, в котором сначала читается и выводится на консоль информация о максимальном количестве рабочих потоков и потоков ввода-вывода. Затем в цикле for метод JobForAThread() назначается потоку из пула потоков за счет вызова метода ThreadPool.QueueUserWorkltem() и передачи делегата типа WaitCallback. Пул потоков получает этот запрос и выбирает из пула один из потоков для вызова метода. Если пул еще не существует, он создается и запускается первый поток:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace ThreadingPools
{
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 5; i++)
{
ThreadPool.QueueUserWorkItem(JobForAThread);
Thread.Sleep(2000);
}
Console.ReadLine();
}
static void JobForAThread(object state)
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine("Цикл {0}, выполняется внутри потока {1}", i,
Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(10);
}
}
}
}
Результат выполнения работ программы представлен на Рис. 4.1.
(рис 4.1) Результаты выполнения пула потоков
Преимущества CLR потоков:
Пулы потоков очень просты в применении, однако обладают рядом ограничений, которые перечислены ниже:
Всего различают две разновидности многозадачности: на основе процессов и на основе потоков. Отличия многозадачности на основе процессов и потоков сводится к следующему: многозадачность на основе процессов организуется для параллельного выполнения программ, а многозадачность на основе потоков - для параллельного выполнения отдельных частей одной программы. В .NET Framework поддерживаются обе разновидности многозадачности: на основе процессов и на основе потоков. Поэтому можно создавать как процессы, так и потоки, а также управлять и теми и другими.
Классы, поддерживающие многопоточное программирование, определены в пространстве имен System.Threading. Поэтому любая многопоточная программа включает в себя следующую строку кода (C#):
using System.Threading;
Пространство имен System.Threading содержит различные типы, позволяющие создавать многопоточные приложения. Одним из основных классов в данном пространстве имен является класс Thread.
Класс Thread является самым элементарным из всех типов пространства имен System.Threading. Основные свойства и методы класса Thread приведены в таблице ниже.
| Имя | Описание |
|---|---|
CurrentContext
|
Это свойство только для чтения возвращает контекст, в котором в данный момент выполняется поток |
CurrentThread |
Это свойство только для чтения возвращает ссылку на текущий выполняемый поток |
GetDomain(), GetDomainID()
|
Этот метод возвращает ссылку на текущий AppDomain или идентификатор этого домена, в котором выполняется текущий поток |
Sleep()
|
Этот метод приостанавливает текущий поток на заданное время |
IsAlive |
Возвращает булевское значение, указывающее на то, запущен ли поток (и еще не прерван и не отменен) |
IsBackground |
Получает или устанавливает значение, указывающее, является ли данный поток "фоновым" (подробнее объясняется далее) |
Name |
Позволяет вам установить дружественное текстовое имя потока |
Priority |
Получает или устанавливает приоритет потока, который может принимать значение из перечисления ThreadPriority |
ThreadState |
Получает состояние данного потока, которому может быть присвоено значение из перечисления ThreadState |
Abort() |
Инструктирует CLR прервать поток, как только это будет возможно |
Interrupt() |
Прерывает (т.е. приостанавливает) текущий поток на заданный период ожидания |
Join() |
Блокирует вызывающий поток до тех пор, пока указанный поток (тот, для которого вызван Join()) не завершится |
Resume() |
Возобновляет ранее приостановленный поток |
Start() |
Инструктирует CLR запустить поток как можно скорее |
Suspend() |
Приостанавливает поток. Если поток уже приостановлен, вызов Suspend() не дает эффекта |
При создании многопоточного приложения, необходимо, руководствоваться следующими шагами:
ParametrizedThreadStart (или ThreadStart), передав конструктору метод, который определен на предыдущем шаге.
ParametrizedThreadStart/ThreadStart.
Thread.Start(). Это действие запустит поток на методе, который указан делегатом, созданным на втором шаге, как только это будет возможно. Всего различают два типа потоков:
Thread.Start(), автоматически становится потоком переднего плана. Данный тип потоков обеспечивают предохранение текущего приложения от завершения. Среда CLR не остановит приложение до тех пор, пока не будут завершены все приоритетные потоки.
IsBackground значение true.Для того что бы присвоить потоку приоритет, нужно использовать свойство Priority в классе Thread, которое определяет, сколько времени на исполнение будет выделено потоку относительно других потоков того же процесса. Существует 5 градаций приоритета потока:
enum ThreadPriority { Lowest, BelowNormal, Normal, AboveNormal, Highest }
Значение приоритета становится существенным, когда одновременно исполняются несколько потоков. Установка приоритета потока на максимум еще не означает работу в реальном времени (real-time), так как существуют еще приоритет процесса приложения. Для того, чтобы поток работал в режиме реального времени (real-time), используется класс Process из пространства имен System.Diagnostics для поднятия приоритета:
Process.GetCurrentProcess().PriorityClass = ProcessPriorityClass.High;
От ProcessPriorityClass.High один шаг до наивысшего приоритета процесса - Realtime. При использовании процесса в режиме приоритета Realtime, то процесс никогда не вытиснится, и если программа случайно попадет в бесконечный цикл, операционная система может быть полностью заблокирована. Спасти вас в этом случае сможет только кнопка выключения питания или перезагрузки. По этой причине ProcessPriorityClass.High считается максимальным приоритетом процесса, рекомендованным к использованию.
Поток создается за счет вызова метода Start() объекта Thread. Однако после вызова метода Start() новый поток все еще пребывает в состоянии Unstarted. В состояние Running поток переходит сразу после того, как планировщик потоков операционной системы выберет его для выполнения. Информация о текущем состоянии потока доступна через свойство Thread.ThreadState.
С помощью метода Thread.Sleep() поток можно перевести в состояние WaitSleepJoin и при этом указать, через какой промежуток времени поток должен возобновить работу:
thread.Sleep(1000);
Для прерывания работы потока, используется метод Thread.Abort():
thread.Abort()
При вызове этого метода в соответствующем потоке генерируется исключение типа ThreadAbortException в том потоке, для которого он был вызван. Это исключение приводит к прерыванию потока и может быть перехвачено и в коде-программы, но в этом случае оно автоматически генерируется еще раз, чтобы остановить поток. Метод Abort() не всегда способен остановить поток немедленно, поэтому если поток требуется остановить перед тем, как продолжить выполнение программы, то после метода Abort() следует сразу же вызвать метод Join().Кроме того, в самых редких случаях методу Abort() вообще не удается остановить поток. Это происходит, например, в том случае, если кодовый блок finally входит в бесконечный цикл.
Запрос на преждевременное прерывание может быть переопределен в самом потоке. Для этого необходимо сначала перехватить в потоке исключение ThreadAbortException, а затем вызвать метод ResetAbort(). Благодаря этому исключается повторное генерирование исключения по завершении обработчика исключения, прерывающего данный поток. Ниже приведена форма объявления метода ResetAbort():
Thread.ResetAbort();
Вызов метода ResetAbort() может завершиться неудачно, если в потоке отсутствует надлежащий режим надежной отмены преждевременного прерывания потока.
При использовании различных коротких задач, подлежащие выполнению, можно заранее создать набор потоков и затем просто отправлять соответствующие запросы, когда наступает очередь для их выполнения, т.е. если количество этих потоков автоматически увеличивалось с ростом необходимости в этих потоках и уменьшалось при возникновении потребности в освобождении ресурсов.
Для управления списком потоков предусмотрен класс ThreadPool, который по мере необходимости уменьшает и увеличивает количество потоков в пуле до максимально допустимого значения. Значение максимально допустимого количества потоков в пуле может изменяться. В случае двуядерного ЦП оно по умолчанию составляет 1023 рабочих потоков и 1000 потоков ввода-вывода.
Для того, чтобы запросить поток из пула для обработки вызова метода, можно использовать метод QueueUserWorkItem(). Этот метод перегружен, чтобы в дополнение к экземпляру делегата WaitCallback позволить указывать необязательный параметр System.Object для специальных данных состояния.
Ниже приведен пример приложения, в котором сначала читается и выводится на консоль информация о максимальном количестве рабочих потоков и потоков ввода-вывода. Затем в цикле for метод JobForAThread() назначается потоку из пула потоков за счет вызова метода ThreadPool.QueueUserWorkltem() и передачи делегата типа WaitCallback. Пул потоков получает этот запрос и выбирает из пула один из потоков для вызова метода. Если пул еще не существует, он создается и запускается первый поток:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace ThreadingPools
{
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 5; i++)
{
ThreadPool.QueueUserWorkItem(JobForAThread);
Thread.Sleep(2000);
}
Console.ReadLine();
}
static void JobForAThread(object state)
{
for (int i = 0; i < 10; i++)
{
Console.WriteLine("Цикл {0}, выполняется внутри потока {1}", i,
Thread.CurrentThread.ManagedThreadId);
Thread.Sleep(10);
}
}
}
}
Результат выполнения работ программы представлен на Рис. 4.1.
(рис 4.1) Результаты выполнения пула потоков
Преимущества CLR потоков:
Пулы потоков очень просты в применении, однако обладают рядом ограничений, которые перечислены ниже:
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.