Многопоточность в C#: Повышение производительности и эффективности
Что такое поток
Поток (thread) — это путь выполнения программы. Каждый поток определяет уникальный поток управления. Если приложение выполняет сложные и длительные операции, полезно разделить выполнение на несколько потоков, каждый из которых выполняет свою задачу.
Потоки — это легковесные процессы. Классический пример — реализация параллельного программирования современными ОС. Использование потоков экономит такты процессора и повышает эффективность приложения.
До сих пор мы писали программы с одним потоком — единственным процессом приложения. Так приложение может выполнять только одну задачу за раз. Чтобы выполнять несколько задач одновременно, её делят на более мелкие потоки.
Жизненный цикл потока
Жизненный цикл начинается при создании объекта System.Threading.Thread и заканчивается при завершении или прерывании потока.
Основные состояния:
Unstarted (Не запущен) — экземпляр создан, но метод Start не вызван.
Ready (Готов) — поток готов к выполнению и ждёт процессорного времени.
Not Runnable (Не выполняется) — поток не может выполняться, если:
- вызван метод Sleep
- вызван метод Wait
- блокирован операциями ввода-вывода
Dead (Завершён) — поток завершил выполнение или был прерван.
Главный поток
В C# для работы с потоками используется класс System.Threading.Thread. Он позволяет создавать и управлять отдельными потоками. Первый поток в процессе называется главным (main thread).
При запуске программы главный поток создаётся автоматически. Потоки, созданные через класс Thread, называются дочерними. Доступ к текущему потоку предоставляет свойство CurrentThread.
Пример работы с главным потоком:
Live Demousing System;
using System.Threading;
namespace MultithreadingApplication {
class MainThreadProgram {
static void Main(string[] args) {
Thread th = Thread.CurrentThread;
th.Name = "MainThread";
Console.WriteLine("This is {0}", th.Name);
Console.ReadKey();
}
}
}
Результат:
This is MainThread
Свойства и методы класса Thread
Наиболее часто используемые свойства:
| № | Свойство и описание |
|---|---|
| 1 | CurrentContext — текущий контекст выполнения потока. |
| 2 | CurrentCulture — культура текущего потока. |
| 3 | CurrentPrincipal — текущий участник для ролевой безопасности. |
| 4 | CurrentThread — текущий выполняющийся поток. |
| 5 | CurrentUICulture — культура для Resource Manager. |
| 6 | ExecutionContext — информация о контекстах потока. |
| 7 | IsAlive — статус выполнения потока. |
| 8 | IsBackground — является ли поток фоновым. |
| 9 | IsThreadPoolThread — принадлежит ли поток пулу. |
| 10 | ManagedThreadId — уникальный идентификатор управляемого потока. |
| 11 | Name — имя потока. |
| 12 | Priority — приоритет планирования. |
| 13 | ThreadState — состояния потока. |
Наиболее часто используемые методы:
| № | Метод и описание |
|---|---|
| 1 | Abort() — начинает процесс завершения потока через ThreadAbortException. |
| 2 | Start() — запускает поток. |
| 3 | Sleep(ms) — приостанавливает поток на указанное время. |
| 4 | Join() — блокирует вызывающий поток до завершения данного. |
| 5 | Interrupt() — прерывает поток в состоянии WaitSleepJoin. |
| 6 | ResetAbort() — отменяет запрос Abort. |
| 7 | VolatileRead/Write — чтение/запись с гарантией видимости для всех процессоров. |
| 8 | MemoryBarrier() — синхронизация доступа к памяти. |
| 9 | Yield() — передаёт управление другому готовому потоку. |
Создание потоков
Потоки создаются через класс Thread. Расширенный класс вызывает Start() для запуска дочернего потока.
Live Demousing System;
using System.Threading;
namespace MultithreadingApplication {
class ThreadCreationProgram {
public static void CallToChildThread() {
Console.WriteLine("Child thread starts");
}
static void Main(string[] args) {
ThreadStart childref = new ThreadStart(CallToChildThread);
Console.WriteLine("In Main: Creating the Child thread");
Thread childThread = new Thread(childref);
childThread.Start();
Console.ReadKey();
}
}
}
Результат:
In Main: Creating the Child thread Child thread starts
Управление потоками
Класс Thread предоставляет методы управления. Пример использования Sleep() для паузы:
Live Demousing System;
using System.Threading;
namespace MultithreadingApplication {
class ThreadCreationProgram {
public static void CallToChildThread() {
Console.WriteLine("Child thread starts");
int sleepfor = 5000;
Console.WriteLine("Child Thread Paused for {0} seconds", sleepfor / 1000);
Thread.Sleep(sleepfor);
Console.WriteLine("Child thread resumes");
}
static void Main(string[] args) {
ThreadStart childref = new ThreadStart(CallToChildThread);
Console.WriteLine("In Main: Creating the Child thread");
Thread childThread = new Thread(childref);
childThread.Start();
Console.ReadKey();
}
}
}
Результат:
In Main: Creating the Child thread Child thread starts Child Thread Paused for 5 seconds Child thread resumes
Уничтожение потоков
Метод Abort() используется для завершения потоков. Среда выполнения выбрасывает ThreadAbortException. Это исключение нельзя перехватить, управление передаётся в блок finally (если есть).
Live Demousing System;
using System.Threading;
namespace MultithreadingApplication {
class ThreadCreationProgram {
public static void CallToChildThread() {
try {
Console.WriteLine("Child thread starts");
for (int counter = 0; counter <= 10; counter++) {
Thread.Sleep(500);
Console.WriteLine(counter);
}
Console.WriteLine("Child Thread Completed");
} catch (ThreadAbortException e) {
Console.WriteLine("Thread Abort Exception");
} finally {
Console.WriteLine("Couldn't catch the Thread Exception");
}
}
static void Main(string[] args) {
ThreadStart childref = new ThreadStart(CallToChildThread);
Console.WriteLine("In Main: Creating the Child thread");
Thread childThread = new Thread(childref);
childThread.Start();
Thread.Sleep(2000);
Console.WriteLine("In Main: Aborting the Child thread");
childThread.Abort();
Console.ReadKey();
}
}
}
Результат (может варьироваться):
In Main: Creating the Child thread Child thread starts 0 1 2 In Main: Aborting the Child thread Thread Abort Exception Couldn't catch the Thread Exception
Язык C
- Малая vs большая диаметры резьбы: как выбрать правильный размер винта
- Нить: виды, история, производство и контроль качества
- Thread vs ZigBee: техническое сравнение для IoT-инженеров
- Выбор правильной нитевой обработки: Повышение надежности и сокращение простоя
- Освоение многопоточности в C++: эффективное параллельное программирование
- Многопоточное программирование в Python: эффективные техники параллелизма
- Периферийные вычисления получают четкий, отраслево одобренный фреймворк
- Быстрая обратная засветка: съемка более 1 миллиона кадров в секунду
- Распутывание цифровой нити: план Siemens PLM для умного производства
- Понимание резаков нитей: типы, использование и применения