English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

C# базовый учебник

C# продвинутый учебник

C#面向对象(OOP)

Многоядерность в C#

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

ПотокиЛегковесные процессыОбщий пример использования потоков - параллельное программирование в современных операционных системах. Использование потоков экономит время ЦП и увеличивает эффективность приложений.

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

Жизненный цикл потока

Жизненный цикл потока начинается с момента создания объекта System.Threading.Thread и заканчивается при终止е или завершении выполнения потока.

Ниже приведен список различных состояний жизни потока:

  • Состояние не запущено:Состояние, при котором пример строки создан, но метод Start еще не вызван.

  • Состояние готовности:Состояние, при котором поток готов к выполнению и ждет周期的 CPU.

  • Состояние, при котором поток не может выполняться:В следующих случаях поток не может выполняться:

    • Метод Sleep уже вызван

    • Метод Wait уже вызван

    • Заблокирован I/O операциями

  • Состояние смерти:Состояние, при котором строка завершена или прервана.

Main thread

В C#,System.Threading.Thread Класс предназначен для работы с потоками. Он позволяет создавать и обращаться к отдельным потокам в многопоточных приложениях. Поток, который的第一个 выполняется в процессе, называетсяMain thread.

При запуске C# программы главный поток автоматически создается. Используйте: Thread Класс созданного потока вызывается подпотоком главного потока. Вы можете использовать класс Thread для: CurrentThread Доступ к свойствам потока.

Ниже приведен пример программы, демонстрирующей выполнение главного потока.

using 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 класса.

В таблице ниже приведены Thread Некоторые часто используемые методы класса Атрибуты:

АтрибутыОписание
CurrentContextПолучить текущий контекст, в котором выполняется строка.
CurrentCultureПолучить или установить текущую региональную информацию текущей строки.
CurrentPrincipalПолучить или установить текущего ответственного за строку (для основанной на ролях безопасности).
CurrentThreadПолучить текущую строку, которая выполняется.
CurrentUICultureПолучить или установить текущую региональную информацию, используемую ресурсом, чтобы найти регионально специфические ресурсы в време.
ExecutionContextПолучить объект ExecutionContext, который содержит информацию о различных контекстах текущей строки.
IsAliveПолучить значение, указывающее текущее состояние выполнения текущей строки.
IsBackgroundПолучить или установить значение, указывающее, является ли определенная строка фоновым процессом.
IsThreadPoolThreadПолучить значение, которое указывает, является ли поток частью托管 пула потоков.
ManagedThreadIdПолучить уникальный идентификатор текущего托管 потока.
NameПолучить или установить имя потока.
PriorityПолучить или установить значение, которое указывает на приоритет планирования потока.
ThreadStateПолучить значение, которое содержит текущее состояние потока.

В таблице ниже приведены Thread Некоторые часто используемые методы класса Метод:

НомерИмя метода & описание
1public void Abort()
В THROW ThreadAbortException в текущем потоке, чтобы начать процесс завершения этого потока. Вызов этого метода обычно завершает поток.
2public static LocalDataStoreSlot AllocateDataSlot()
Ассигновать неименованный слот данных для всех потоков. Для улучшения производительности, пожалуйста, измените использование полей, помеченных атрибутом ThreadStaticAttribute.
3public static LocalDataStoreSlot AllocateNamedDataSlot( string name)
Ассигновать уже назначенный слот данных для всех потоков. Для улучшения производительности, пожалуйста, измените использование полей, помеченных атрибутом ThreadStaticAttribute.
4public static void BeginCriticalRegion()
Уведомлять хост-код, что он будет входить в область кода, где прерывание потока или необработанные исключения могут угрожать другим задачам в домене приложения.
5public static void BeginThreadAffinity()
Уведомлять хост-код, что он будет выполнять инструкции, зависимые от текущего физического операционной системы потока.
6public static void EndCriticalRegion()
Уведомлять хост-код, что он будет входить в область кода, где прерывание потока или необработанные исключения влияют только на текущую задачу.
7public static void EndThreadAffinity()
Уведомлять хост-код, что инструкции, зависимые от текущего физического операционной системы потока, уже выполнены.
8public static void FreeNamedDataSlot(string name)
Удалять связь между именем и слотом для всех потоков в процессе. Для улучшения производительности, пожалуйста, измените использование полей, помеченных атрибутом ThreadStaticAttribute.
9public static Object GetData( LocalDataStoreSlot slot )
retrieve the value from the specified slot in the current domain of the current thread. For better performance, please use fields marked with the ThreadStaticAttribute attribute.
10public static AppDomain GetDomain()
return the current domain in which the current thread is running.
11public static AppDomain GetDomainID()
return a unique application domain identifier.
12public static LocalDataStoreSlot GetNamedDataSlot( string name )
find the named data slot. For better performance, please use fields marked with the ThreadStaticAttribute attribute.
13public void Interrupt()
interrupt the thread in the WaitSleepJoin thread state.
14public void Join()
block the calling thread during the execution of standard COM and SendMessage message pump processing until a thread terminates. This method has different overloads.
15public static void MemoryBarrier()
synchronize memory access as follows: when the processor of the current thread performs instruction reordering, it cannot use the method of executing memory access after the MemoryBarrier call before executing memory access before the MemoryBarrier call.
16public static void ResetAbort()
cancel the Abort requested for the current thread.
17public static void SetData( LocalDataStoreSlot slot, Object data )
set data in the specified slot for the current domain of this thread running on the current thread. For better performance, please use fields marked with the ThreadStaticAttribute attribute.
18public void Start()
start a thread.
19public static void Sleep( int millisecondsTimeout )
pause the thread for a while.
20public static void SpinWait( int iterations )
Влечет за собой ожидание потока в течение времени, определенного параметром iterations.
21public 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 )

Чтение значения поля. Независимо от числа процессоров или состояния кэша процессора, значение является последним, записанным любым процессором компьютера. Этот метод имеет различные формы overload. В данном случае приведены только некоторые из них.
22public static void VolatileWrite( ref byte address, 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 )

Сразу записать значение в поле, чтобы сделать его видимым для всех процессоров в компьютере. Этот метод имеет различные формы overload. В данном случае приведены только некоторые из них.
23public static bool Yield();
Влечет за собой запуск выполнения другого потока, готового к выполнению на текущем процессоре. Выбор потока для выполнения осуществляется операционной системой.

Создание потока

Потоки создаются расширением класса Thread. Расширенный класс Thread вызывает Start(); Метод для запуска выполнения подпотока.

Ниже приведен пример программы, демонстрирующей этот концепцию:

using System;
using System.Threading;
namespace MultithreadingApplication
{
    class ThreadCreationProgram
    {
        public static void CallToChildThread()
        {
            Console.WriteLine("Дочерняя нить начинается");
        }
        
        static void Main(string[] args)
        {
            ThreadStart childref = new ThreadStart(CallToChildThread);
            Console.WriteLine("В Main: Создание дочерней нити");
            Thread childThread = new Thread(childref);
            childThread.Start();
            Console.ReadKey();
        }
    }
}

Когда上面的 код будет компилироваться и выполняться, он произведет следующий результат:

В Main: создание child потока
Child поток начинается

Управление потоками

Класс Thread предоставляет различные методы для управления потоками.

Ниже приведен пример: sleep(); Метод используется для приостановки выполнения потока в течение определенного времени.

using System;
using System.Threading;
namespace MultithreadingApplication
{
    class ThreadCreationProgram
    {
        public static void CallToChildThread()
        {
            Console.WriteLine("Дочерняя нить начинается");
            // Thread pause 5000 milliseconds
            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("В Main: Создание дочерней нити");
            Thread childThread = new Thread(childref);
            childThread.Start();
            Console.ReadKey();
        }
    }
}

Когда上面的 код будет компилироваться и выполняться, он произведет следующий результат:

В Main: создание child потока
Child поток начинается
Дочерняя нить приостановлена на 5 секунд
Дочерняя нить возобновляет работу

разрушить нить

Abort() метод предназначен для разрушения нити.

через выброс threadabortexception Прекратить выполнение нити в режиме выполнения. Этот исключение не может быть перехвачен, если finally блок, управление будет передано finally блок.

Ниже приведен пример программы, которая это демонстрирует:

using System;
using System.Threading;
namespace MultithreadingApplication
{
    class ThreadCreationProgram
    {
        public static void CallToChildThread()
        {
            try
            {
                Console.WriteLine("Дочерняя нить начинается");
                // Счет до 10
                for(int counter = 0; counter <= 10; counter++)
                {
                    Thread.Sleep(500);
                    Console.WriteLine(counter);
                }
                Console.WriteLine("Дочерняя нить завершена");
            }
            catch(ThreadAbortException e)
            {
                Console.WriteLine("Исключение abort нити");
            }
            finally
            {
                Console.WriteLine("Не удалось перехватить исключение нити");
            }
        }
        
        static void Main(string[] args)
        {
            ThreadStart childref = new ThreadStart(CallToChildThread);
            Console.WriteLine("В Main: Создание дочерней нити");
            Thread childThread = new Thread(childref);
            childThread.Start();
            // Остановить главную нить на время
            Thread.Sleep(2000);
            // Теперь中止子线程
            Console.WriteLine("В Main: Отмена дочерней нити");
            childThread.Abort();
            Console.ReadKey();
        }
    }
}

Когда上面的 код будет компилироваться и выполняться, он произведет следующий результат:

В Main: создание child потока
Child поток начинается
0
1
2
В Main: abort child потока
Исключение abort потока
Не удалось перехватить исключение потока