C# Многопоточность
ПотокПоток определяется как путь выполнения программы. Каждый поток определяет уникальный поток управления. Если ваше приложение включает сложные и длительные операции, часто полезно настроить различные пути выполнения потоков, при этом каждый поток выполняет конкретную работу.
Поток — этоЛегковесный процессРаспространённым примером использования потоков является реализация параллельного программирования в современных операционных системах. Использование потоков позволяет избежать напрасной траты циклов CPU и повышает эффективность приложений.
Программы, которые мы написали до сих пор, выполняются как один процесс с одним потоком в качестве выполняющегося экземпляра приложения. Однако таким образом приложение может выполнять только одну задачу за раз. Чтобы выполнять несколько задач одновременно, его можно разделить на более мелкие потоки.
Жизненный цикл потока
Жизненный цикл потока начинается, когда создается объект класса System.Threading.Thread, и заканчивается, когда поток завершается или завершает выполнение.
Различные состояния в жизненном цикле потока перечислены ниже:
- Незапущенное состояние: состояние, когда экземпляр потока создан, но метод Start не был вызван.
- Состояние готовности: состояние, когда поток готов к выполнению и ожидает цикла процессора.
- Неисполняемое состояние: Поток не может выполняться в следующих случаях:
- Был вызван метод Sleep
- Был вызван метод Wait
- Заблокирован операцией ввода-вывода
- Состояние завершения: состояние, когда поток завершил выполнение или был прерван.
главный поток
В C#,System.Threading.ThreadКласс Thread используется для работы с потоками. Он позволяет создавать отдельные потоки и получать доступ к ним в многопоточном приложении. Первый поток, выполняемый в процессе, называется главным потоком.главный поток。
Когда программа на C# начинает выполнение, главный поток создается автоматически. ИспользуяThread, потоки, созданные классом, называются дочерними потоками главного потока. Вы можете использовать свойствоCurrentThreadкласса Thread для доступа к потоку.
Следующая программа демонстрирует выполнение главного потока:
Пример
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
В таблице ниже перечисленыThreadнекоторые общие методы классаProperty:
| Свойство | Описание |
|---|---|
| CurrentContext | Возвращает текущий контекст, в котором выполняется поток. |
| CurrentCulture | Возвращает или задает культуру текущего потока. |
| CurrentPrincipal | Возвращает или задает текущий субъект потока (для безопасности на основе ролей). |
| CurrentThread | Возвращает текущий выполняющийся поток. |
| CurrentUICulture | Возвращает или задает текущую культуру, используемую диспетчером ресурсов для поиска ресурсов, зависящих от культуры, во время выполнения. |
| ExecutionContext | Возвращает объект ExecutionContext, содержащий контекстную информацию о текущем потоке. |
| IsAlive | Возвращает значение, указывающее состояние выполнения текущего потока. |
| IsBackground | Возвращает или задаёт значение, указывающее, является ли поток фоновым. |
| IsThreadPoolThread | Возвращает значение, указывающее, принадлежит ли поток управляемому пулу потоков. |
| ManagedThreadId | Возвращает уникальный идентификатор текущего управляемого потока. |
| Name | Возвращает или задаёт имя потока. |
| Приоритет | Возвращает или задаёт значение, указывающее приоритет планирования потока. |
| ThreadState | Возвращает значение, содержащее состояние текущего потока. |
В таблице ниже перечисленыThreadнекоторые распространённые методы классаМетоды:
| Порядковый номер | Название метода & описание |
|---|---|
| 1 | public void Abort() Вызывает ThreadAbortException в потоке, в котором вызывается этот метод, чтобы начать процесс завершения этого потока. Вызов этого метода обычно завершает поток. |
| 2 | public static LocalDataStoreSlot AllocateDataSlot() Выделяет неименованный слот данных во всех потоках. Для повышения производительности вместо этого используйте поля, помеченные атрибутом ThreadStaticAttribute. |
| 3 | public static LocalDataStoreSlot AllocateNamedDataSlot(
string name)
Выделяет именованный слот данных во всех потоках. Для повышения производительности вместо этого используйте поля, помеченные атрибутом ThreadStaticAttribute. |
| 4 | public static void BeginCriticalRegion() Уведомляет хост о том, что выполнение собирается войти в область кода, в которой последствия прерываний потоков или необработанных исключений могут поставить под угрозу другие задачи в домене приложения. |
| 5 | public static void BeginThreadAffinity() Уведомляет хост о том, что управляемый код собирается выполнить инструкции, которые зависят от идентификатора текущего физического потока операционной системы. |
| 6 | public static void EndCriticalRegion() Уведомляет хост о том, что выполнение собирается войти в область кода, в которой прерывания потоков или необработанные исключения влияют только на текущую задачу. |
| 7 | public static void EndThreadAffinity() Уведомляет хост о том, что управляемый код завершил выполнение инструкций, зависящих от идентификатора текущего физического потока операционной системы. |
| 8 | public static void FreeNamedDataSlot(string name) Удаляет связь между именами и слотами для всех потоков в процессе. Для повышения производительности вместо этого используйте поля, помеченные атрибутом ThreadStaticAttribute. |
| 9 | public static Object GetData(
LocalDataStoreSlot slot
)
Извлекает значение из указанного слота в текущем потоке в пределах текущего домена текущего потока. Для повышения производительности вместо этого используйте поля, помеченные атрибутом ThreadStaticAttribute. |
| 10 | public static AppDomain GetDomain() Возвращает текущий домен, в котором выполняется текущий поток. |
| 11 | public static AppDomain GetDomainID() Возвращает уникальный идентификатор домена приложения. |
| 12 | public static LocalDataStoreSlot GetNamedDataSlot(
string name
)
Выполняет поиск именованного слота данных. Для повышения производительности вместо этого используйте поля, помеченные атрибутом ThreadStaticAttribute. |
| 13 | public void Interrupt() Прерывает поток, находящийся в состоянии потока WaitSleepJoin. |
| 14 | public void Join() Блокирует вызывающий поток до завершения потока, продолжая при этом выполнять стандартную перекачку сообщений COM и SendMessage. Этот метод имеет различные перегруженные формы. |
| 15 | public static void MemoryBarrier() Синхронизирует доступ к памяти следующим образом: процессор, выполняющий текущий поток, не может переупорядочивать инструкции так, чтобы обращения к памяти после вызова MemoryBarrier выполнялись до обращений к памяти, предшествовавших вызову MemoryBarrier. |
| 16 | public static void ResetAbort() Отменяет Abort, запрошенный для текущего потока. |
| 17 | public static void SetData(
LocalDataStoreSlot slot,
Object data
)
Задает данные в указанном слоте текущего выполняющегося потока для текущего домена потока. Для повышения производительности вместо этого используйте поля, помеченные атрибутом ThreadStaticAttribute. |
| 18 | public void Start() Запускает поток. |
| 19 | public static void Sleep(
int millisecondsTimeout
)
Приостанавливает поток на некоторое время. |
| 20 | public static void SpinWait(
int iterations
)
Заставляет поток ожидать в течение времени, определяемого параметром iterations. |
| 21 | public static byte VolatileRead(
ref byte address
) public static double VolatileRead( ref double address ) public static int VolatileRead( ref int address ) public static Object VolatileRead( ref Object address ) Читает поле. Независимо от количества процессоров или состояния процессора, значение является последним значением, записанным любым процессором в компьютере. Этот метод имеет различные перегрузки. Здесь приведены только некоторые формы. |
| 22 | public static void VolatileWrite(
ref byte,
byte value
) public static void VolatileWrite( ref double address, double value ) public static void VolatileWrite( ref int address, int value ) public static void VolatileWrite( ref Object address, Object value ) Немедленно записывает значение в поле, чтобы значение было видно всем процессорам в компьютере. Этот метод имеет различные перегруженные формы. Здесь приведены только некоторые формы. |
| 23 | public static bool Yield() Заставляет вызывающий поток выполнить другой поток, готовый к запуску на текущем процессоре. Поток, который должен быть выполнен, выбирается операционной системой. |
Создание потоков
Потоки создаются путем расширения класса Thread. Расширенный класс Thread вызывает методStart()для запуска выполнения дочернего потока.
Следующая программа демонстрирует эту концепцию:
Пример
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()использование метода для приостановки потока на заданное время.
Пример
using System.Threading;
namespace MultithreadingApplication
{
class ThreadCreationProgram
{
public static void CallToChildThread()
{
Console.WriteLine("Child thread starts");
// Приостановить поток на 5000 миллисекунд
int sleepfor = 5000;
Console.WriteLine("Дочерний поток приостановлен на {0} секунд",
sleepfor / 1000);
Thread.Sleep(sleepfor);
Console.WriteLine("Дочерний поток возобновляет работу");
}
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блок, управление передается вfinallyБлок.
Следующая программа иллюстрирует это:
Пример
using System.Threading;
namespace MultithreadingApplication
{
class ThreadCreationProgram
{
public static void CallToChildThread()
{
try
{
Console.WriteLine("Child thread starts");
// Считать до 10
for (int counter = 0; counter <= 10; counter++)
{
Thread.Sleep(500);
Console.WriteLine(counter);
}
Console.WriteLine("Дочерний поток завершён");
}
catch (ThreadAbortException e)
{
Console.WriteLine("Исключение прерывания потока");
}
finally
{
Console.WriteLine("Не удалось перехватить исключение потока");
}
}
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("В Main: прерывание дочернего потока");
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Другие расширения