Материал: Глава 18. Многопоточное программирование

Внимание! Если размещение файла нарушает Ваши авторские права, то обязательно сообщите нам

Наименование метода

Описание

 

 

 

завершенности потока следует

 

опрашивать его свойство

 

ThreadState4

 

 

Interrupt

Метод, который прерывает поток на

некоторое время5

 

 

 

 

Метод блокирует выполнение

Join

вызвавшего его потока до тех пор,

пока не завершится поток, для

 

 

которого был вызван данный метод6

 

 

Start

Метод запускает поток7

 

 

 

 

Используем вышеописанные свойства и методы для получения

информации о потоке:

 

 

 

 

Листинг 18.1 – Получение информации о потоке

 

 

 

 

 

 

1

using System.Threading;

 

 

 

2

using System.Windows.Forms;

 

 

 

3

namespace WindowsFormsApp13

 

 

 

4

{

 

 

 

5

public partial class Form1 : Form

 

 

 

6

{

 

 

 

7

public Form1()

 

 

 

8

{

 

 

 

9

InitializeComponent();

 

 

 

10

Thread t = Thread.CurrentThread;

 

 

 

11

t.Name = "Метод Main";

 

 

 

12

richTextBoxThreadInfo.Text = $"Имя потока: {t.Name}" +

 

 

 

"\n" +

 

 

 

13

$"Запущен ли поток: {t.IsAlive}" + "\n" +

 

 

 

14

$"Приоритет потока: {t.Priority}" + "\n" +

 

 

 

15

$"Статус потока: {t.ThreadState}" + "\n" +

 

 

 

16

$"Домен

приложения:

 

 

 

{Thread.GetDomain().FriendlyName}";

 

 

4https://docs.microsoft.com/ru-ru/dotnet/api/system.threading.thread.abort?view=net-5.0

5https://docs.microsoft.com/ru-ru/dotnet/api/system.threading.thread.interrupt?view=net-5.0

6https://docs.microsoft.com/ru-ru/dotnet/api/system.threading.thread.join?view=net-5.0

7https://docs.microsoft.com/ru-ru/dotnet/api/system.threading.thread.start?view=net-5.0

6

17}

18}

19}

Вэтом случае мы получим примерно следующий вывод:

Рисунок 18.1 – Вывод состояния потока

Статусы потока содержатся в перечислении ThreadState:

 

Таблица 18.3 – Статусы потока

 

 

Статус потока

Описание статуса

 

 

Aborted

поток остановлен, но пока еще окончательно не

завершен

 

 

 

AbortRequested

для потока вызван метод Abort, но остановка потока

еще не произошла

 

 

 

Background

поток выполняется в фоновом режиме

 

 

Running

поток запущен и работает (не приостановлен)

 

 

Stopped

поток завершен

 

 

StopRequested

поток получил запрос на остановку

 

 

Suspended

поток приостановлен

 

 

SuspendRequested

поток получил запрос на приостановку

 

 

Unstarted

поток еще не был запущен

 

 

WaitSleepJoin

поток заблокирован в результате действия методов

Sleep или Join

 

 

 

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

Running. Вызвав метод Sleep, статус изменится на WaitSleepJoin. А

применяя метод Abort, мы тем самым переведем поток в состояние

7

AbortRequested, а затем Aborted, после чего поток окончательно завершится.

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

тем важнее для процессора предоставить время и ресурсы для выполнения именно ему. Если же приоритет потока не слишком высокий, значит он может и подождать в очереди, пока выполняются более приоритетные потоки.

Приоритеты потоков располагаются в перечислении ThreadPriority:

Lowest – самый низкий

BelowNormal – ниже среднего

Normal – стандартный

AboveNormal – выше среднего

Highest – самый высокий

По умолчанию потоку задается значение Normal. Однако мы можем изменить приоритет в процессе работы программы. Например, повысить важность потока, установив приоритет Highest. Среда CLR будет считывать и анализировать значения приоритета и на их основании выделять данному потоку то или иное количество времени.

§18.2.2 Создание потоков

Используя класс Thread, мы можем выделить в приложении несколько потоков, которые будут выполняться одновременно.

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

Для создания нового потока используется делегат ThreadStart,

который получает в качестве параметра выполняемый метод. И чтобы запустить поток, вызывается метод Start.

Рассмотрим пример:

8

1

using System.Threading;

2

class Program

3

{

4

static void Main(string[] args)

5

{

6

// создаем новый поток

7

Thread myThread = new Thread(new

ThreadStart(Count));

 

8

myThread.Start(); // запускаем поток

9

for (int i = 1; i < 9; i++)

10

{

11

Console.WriteLine("Главный поток:");

12

Console.WriteLine(i * i);

13

Thread.Sleep(300);

14

}

15

Console.ReadLine();

16

}

17

public static void Count()

18

{

19

for (int i = 1; i < 9; i++)

20

{

21

Console.WriteLine("Второй поток:");

22

Console.WriteLine(i + i);

23

Thread.Sleep(400);

24

}

25

}

26

}

Здесь новый поток будет производить действия, определенные в методе

Count. В данном случае это возведение в квадрат числа и вывод его на экран.

И после каждого умножения с помощью метода Thread.Sleep мы усыпляем поток на 400 миллисекунд.

Чтобы запустить этот метод в качестве второго потока, мы сначала создаем объект потока:

Thread myThread = new Thread(new ThreadStart(Count));.

В конструктор передается делегат ThreadStart, который в качестве параметра принимает метод Count. И следующей строкой

myThread.Start()

9

мы запускаем поток. После этого управление передается главному потоку, и

выполняются все остальные действия, определенные в методе Main.

Таким образом, в нашей программе будут работать одновременно главный поток, представленный методом Main, и второй поток. Кроме действий по созданию второго потока, в главном потоке также производятся некоторые вычисления. Как только все потоки отработают, программа завершит свое выполнение.

Подобным образом мы можем создать и три, и четыре, и целый набор новых потоков, которые смогут решать те или иные задачи.

Существует еще одна форма создания потока:

Thread myThread = new Thread(Count);

Хотя в данном случае явным образом мы не используем делегат

ThreadStart, но неявно он создается. Компилятор C# выводит делегат из сигнатуры метода Count и вызывает соответствующий конструктор.

§18.2.3 Примеры работы потоков Пример 1

На примере посмотрим, на что влияет приоритетность потоков в C#. Мы решили взять для примера программу с тремя потоками, каждый из которых будет выводить в консоль цифры от 0 до 9, от 10 до 19 и от 20 до 29

соответственно. Поставим перед собой задачу вывести в консоль все эти числа последовательно от 0 до 29.

Если мы пренебрежем приоритетами при постановке данной задачи, то у нас никак не получится вывести все наши числа по очереди. Так как у всех трёх потоков одинаковый приоритет, процессору, по сути, будет всё равно,

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

Попробуем реализовать всё так, чтобы у нас получился необходимый нам результат.

Листинг 18.2 – Изменение приоритета потоков

10

Источник: https://studfile.net/preview/16573807/