Поделиться через


Класс System.Threading.Thread

В этой статье приводятся дополнительные замечания к справочной документации по этому API.

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

При запуске процесса общая среда выполнения автоматически создает один поток переднего плана для выполнения кода приложения. Наряду с этим основным потоком выполнения процесс может создать один или несколько потоков для выполнения части кода программы, относящегося к процессу. Эти потоки могут выполняться либо на переднем плане, либо в фоновом режиме. Кроме того, можно использовать ThreadPool класс для выполнения кода в рабочих потоках, управляемых средой CLR.

Начать тему

Поток запускается путем предоставления делегата, представляющего метод, который поток выполняется в конструкторе классов. Затем вызывается Start метод для начала выполнения.

Конструкторы Thread могут принимать один из двух типов делегатов в зависимости от того, можно ли передать аргумент в метод для выполнения:

  • Если метод не имеет аргументов, передайте ThreadStart делегат конструктору. Он имеет подпись:

    public delegate void ThreadStart()
    
    Public Delegate Sub ThreadStart()
    

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

    using System;
    using System.Diagnostics;
    using System.Threading;
    
    public class Example2
    {
       public static void Main()
       {
          var th = new Thread(ExecuteInForeground);
          th.Start();
          Thread.Sleep(1000);
          Console.WriteLine($"Main thread ({Thread.CurrentThread.ManagedThreadId}) exiting...");
       }
    
       private static void ExecuteInForeground()
       {
          var sw = Stopwatch.StartNew();
          Console.WriteLine("Thread {0}: {1}, Priority {2}",
                            Thread.CurrentThread.ManagedThreadId,
                            Thread.CurrentThread.ThreadState,
                            Thread.CurrentThread.Priority);
          do {
             Console.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId}: Elapsed {sw.ElapsedMilliseconds / 1000.0:N2} seconds");
             Thread.Sleep(500);
          } while (sw.ElapsedMilliseconds <= 5000);
          sw.Stop();
       }
    }
    // The example displays output like the following:
    //       Thread 3: Running, Priority Normal
    //       Thread 3: Elapsed 0.00 seconds
    //       Thread 3: Elapsed 0.51 seconds
    //       Main thread (1) exiting...
    //       Thread 3: Elapsed 1.02 seconds
    //       Thread 3: Elapsed 1.53 seconds
    //       Thread 3: Elapsed 2.05 seconds
    //       Thread 3: Elapsed 2.55 seconds
    //       Thread 3: Elapsed 3.07 seconds
    //       Thread 3: Elapsed 3.57 seconds
    //       Thread 3: Elapsed 4.07 seconds
    //       Thread 3: Elapsed 4.58 seconds
    
    open System.Diagnostics
    open System.Threading
    
    let executeInForeground () =
        let sw = Stopwatch.StartNew()
    
        printfn $"Thread {Thread.CurrentThread.ManagedThreadId}: {Thread.CurrentThread.ThreadState}, Priority {Thread.CurrentThread.Priority}"
    
        while sw.ElapsedMilliseconds <= 5000 do
            printfn $"Thread {Thread.CurrentThread.ManagedThreadId}: Elapsed {sw.ElapsedMilliseconds / 1000L:N2} seconds"
            Thread.Sleep 500
    
        sw.Stop()
    
    let th = Thread executeInForeground
    th.Start()
    Thread.Sleep 1000
    printfn $"Main thread ({Thread.CurrentThread.ManagedThreadId}) exiting..."
    
    // The example displays output like the following:
    //       Thread 3: Running, Priority Normal
    //       Thread 3: Elapsed 0.00 seconds
    //       Thread 3: Elapsed 0.51 seconds
    //       Main thread (1) exiting...
    //       Thread 3: Elapsed 1.02 seconds
    //       Thread 3: Elapsed 1.53 seconds
    //       Thread 3: Elapsed 2.05 seconds
    //       Thread 3: Elapsed 2.55 seconds
    //       Thread 3: Elapsed 3.07 seconds
    //       Thread 3: Elapsed 3.57 seconds
    //       Thread 3: Elapsed 4.07 seconds
    //       Thread 3: Elapsed 4.58 seconds
    
    Imports System.Diagnostics
    Imports System.Threading
    
    Module Example3
        Public Sub Main()
            Dim th As New Thread(AddressOf ExecuteInForeground)
            th.Start()
            Thread.Sleep(1000)
            Console.WriteLine("Main thread ({0}) exiting...", Thread.CurrentThread.ManagedThreadId)
        End Sub
    
        Private Sub ExecuteInForeground()
            Dim start As DateTime = DateTime.Now
            Dim sw As Stopwatch = Stopwatch.StartNew()
            Console.WriteLine("Thread {0}: {1}, Priority {2}",
                            Thread.CurrentThread.ManagedThreadId,
                            Thread.CurrentThread.ThreadState,
                            Thread.CurrentThread.Priority)
            Do
                Console.WriteLine("Thread {0}: Elapsed {1:N2} seconds",
                               Thread.CurrentThread.ManagedThreadId,
                               sw.ElapsedMilliseconds / 1000)
                Thread.Sleep(500)
            Loop While sw.ElapsedMilliseconds <= 5000
            sw.Stop()
        End Sub
    End Module
    ' The example displays output like the following:
    '       Thread 3: Running, Priority Normal
    '       Thread 3: Elapsed 0.00 seconds
    '       Thread 3: Elapsed 0.51 seconds
    '       Main thread (1) exiting...
    '       Thread 3: Elapsed 1.02 seconds
    '       Thread 3: Elapsed 1.53 seconds
    '       Thread 3: Elapsed 2.05 seconds
    '       Thread 3: Elapsed 2.55 seconds
    '       Thread 3: Elapsed 3.07 seconds
    '       Thread 3: Elapsed 3.57 seconds
    '       Thread 3: Elapsed 4.07 seconds
    '       Thread 3: Elapsed 4.58 seconds
    
  • Если у метода есть аргумент, передайте делегат ParameterizedThreadStart в конструктор. Он имеет подпись:

    public delegate void ParameterizedThreadStart(object obj)
    
    Public Delegate Sub ParameterizedThreadStart(obj As Object)
    

    Затем метод, выполняемый делегатом, может привести (в C#) или преобразовать (в Visual Basic) параметр в соответствующий тип.

    Следующий пример идентичен предыдущему, за исключением того, что вызывает Thread(ParameterizedThreadStart) конструктор. Эта версия метода имеет один параметр, представляющий приблизительное число миллисекунд ExecuteInForeground, за которое предполагается выполнение цикла.

    using System;
    using System.Diagnostics;
    using System.Threading;
    
    public class Example3
    {
       public static void Main()
       {
          var th = new Thread(ExecuteInForeground);
          th.Start(4500);
          Thread.Sleep(1000);
          Console.WriteLine($"Main thread ({Thread.CurrentThread.ManagedThreadId}) exiting...");
       }
    
       private static void ExecuteInForeground(Object obj)
       {
          int interval;
          try {
             interval = (int) obj;
          }
          catch (InvalidCastException) {
             interval = 5000;
          }
          var sw = Stopwatch.StartNew();
          Console.WriteLine("Thread {0}: {1}, Priority {2}",
                            Thread.CurrentThread.ManagedThreadId,
                            Thread.CurrentThread.ThreadState,
                            Thread.CurrentThread.Priority);
          do {
             Console.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId}: Elapsed {sw.ElapsedMilliseconds / 1000.0:N2} seconds");
             Thread.Sleep(500);
          } while (sw.ElapsedMilliseconds <= interval);
          sw.Stop();
       }
    }
    // The example displays output like the following:
    //       Thread 3: Running, Priority Normal
    //       Thread 3: Elapsed 0.00 seconds
    //       Thread 3: Elapsed 0.52 seconds
    //       Main thread (1) exiting...
    //       Thread 3: Elapsed 1.03 seconds
    //       Thread 3: Elapsed 1.55 seconds
    //       Thread 3: Elapsed 2.06 seconds
    //       Thread 3: Elapsed 2.58 seconds
    //       Thread 3: Elapsed 3.09 seconds
    //       Thread 3: Elapsed 3.61 seconds
    //       Thread 3: Elapsed 4.12 seconds
    
    open System
    open System.Diagnostics
    open System.Threading
    
    let executeInForeground obj =
        let interval =
            try
                unbox<int> obj
            with :? InvalidCastException ->
                5000
    
        let sw = Stopwatch.StartNew()
    
        printfn $"Thread {Thread.CurrentThread.ManagedThreadId}: {Thread.CurrentThread.ThreadState}, Priority {Thread.CurrentThread.Priority}"
    
        while sw.ElapsedMilliseconds <= interval do
            printfn $"Thread {Thread.CurrentThread.ManagedThreadId}: Elapsed {sw.ElapsedMilliseconds / 1000L:N2} seconds"
            Thread.Sleep 500
    
        sw.Stop()
    
    let th = Thread(ParameterizedThreadStart executeInForeground)
    th.Start 4500
    Thread.Sleep 1000
    printfn $"Main thread ({Thread.CurrentThread.ManagedThreadId}) exiting..."
    
    // The example displays output like the following:
    //       Thread 3: Running, Priority Normal
    //       Thread 3: Elapsed 0.00 seconds
    //       Thread 3: Elapsed 0.52 seconds
    //       Main thread (1) exiting...
    //       Thread 3: Elapsed 1.03 seconds
    //       Thread 3: Elapsed 1.55 seconds
    //       Thread 3: Elapsed 2.06 seconds
    //       Thread 3: Elapsed 2.58 seconds
    //       Thread 3: Elapsed 3.09 seconds
    //       Thread 3: Elapsed 3.61 seconds
    //       Thread 3: Elapsed 4.12 seconds
    
    Imports System.Diagnostics
    Imports System.Threading
    
    Module Example4
        Public Sub Main()
            Dim th As New Thread(AddressOf ExecuteInForeground)
            th.Start(4500)
            Thread.Sleep(1000)
            Console.WriteLine("Main thread ({0}) exiting...", Thread.CurrentThread.ManagedThreadId)
        End Sub
    
        Private Sub ExecuteInForeground(obj As Object)
            Dim interval As Integer
            If IsNumeric(obj) Then
                interval = CInt(obj)
            Else
                interval = 5000
            End If
            Dim start As DateTime = DateTime.Now
            Dim sw As Stopwatch = Stopwatch.StartNew()
            Console.WriteLine("Thread {0}: {1}, Priority {2}",
                            Thread.CurrentThread.ManagedThreadId,
                            Thread.CurrentThread.ThreadState,
                            Thread.CurrentThread.Priority)
            Do
                Console.WriteLine("Thread {0}: Elapsed {1:N2} seconds",
                               Thread.CurrentThread.ManagedThreadId,
                               sw.ElapsedMilliseconds / 1000)
                Thread.Sleep(500)
            Loop While sw.ElapsedMilliseconds <= interval
            sw.Stop()
        End Sub
    End Module
    ' The example displays output like the following:
    '       Thread 3: Running, Priority Normal
    '       Thread 3: Elapsed 0.00 seconds
    '       Thread 3: Elapsed 0.52 seconds
    '       Main thread (1) exiting...
    '       Thread 3: Elapsed 1.03 seconds
    '       Thread 3: Elapsed 1.55 seconds
    '       Thread 3: Elapsed 2.06 seconds
    '       Thread 3: Elapsed 2.58 seconds
    '       Thread 3: Elapsed 3.09 seconds
    '       Thread 3: Elapsed 3.61 seconds
    '       Thread 3: Elapsed 4.12 seconds
    

Не нужно сохранять ссылку на объект Thread, после того как вы запустили поток. Поток продолжает выполняться до завершения функции потока.

Получение объектов Thread

Вы можете использовать статическое свойство (Shared в Visual Basic) CurrentThread для получения ссылки на текущий выполняемый поток из кода, выполняемого потоком. В следующем примере CurrentThread свойство используется для отображения сведений о главном потоке приложения, другом потоке переднего плана, фоновом потоке и потоке пула потоков.

using System;
using System.Threading;

public class Example1
{
   static Object obj = new Object();
   
   public static void Main()
   {
      ThreadPool.QueueUserWorkItem(ShowThreadInformation);
      var th1 = new Thread(ShowThreadInformation);
      th1.Start();
      var th2 = new Thread(ShowThreadInformation);
      th2.IsBackground = true;
      th2.Start();
      Thread.Sleep(500);
      ShowThreadInformation(null); 
   }
   
   private static void ShowThreadInformation(Object state)
   {
      lock (obj) {
         var th  = Thread.CurrentThread;
         Console.WriteLine($"Managed thread #{th.ManagedThreadId}: ");
         Console.WriteLine($"   Background thread: {th.IsBackground}");
         Console.WriteLine($"   Thread pool thread: {th.IsThreadPoolThread}");
         Console.WriteLine($"   Priority: {th.Priority}");
         Console.WriteLine($"   Culture: {th.CurrentCulture.Name}");
         Console.WriteLine($"   UI culture: {th.CurrentUICulture.Name}");
         Console.WriteLine();
      }   
   }
}
// The example displays output like the following:
//       Managed thread #6:
//          Background thread: True
//          Thread pool thread: False
//          Priority: Normal
//          Culture: en-US
//          UI culture: en-US
//       
//       Managed thread #3:
//          Background thread: True
//          Thread pool thread: True
//          Priority: Normal
//          Culture: en-US
//          UI culture: en-US
//       
//       Managed thread #4:
//          Background thread: False
//          Thread pool thread: False
//          Priority: Normal
//          Culture: en-US
//          UI culture: en-US
//       
//       Managed thread #1:
//          Background thread: False
//          Thread pool thread: False
//          Priority: Normal
//          Culture: en-US
//          UI culture: en-US
open System.Threading

let obj = obj ()

let showThreadInformation (state: obj) =
    lock obj (fun () ->
        let th = Thread.CurrentThread
        printfn $"Managed thread #{th.ManagedThreadId}: "
        printfn $"   Background thread: {th.IsBackground}"
        printfn $"   Thread pool thread: {th.IsThreadPoolThread}"
        printfn $"   Priority: {th.Priority}"
        printfn $"   Culture: {th.CurrentCulture.Name}"
        printfn $"   UI culture: {th.CurrentUICulture.Name}"
        printfn "")

ThreadPool.QueueUserWorkItem showThreadInformation |> ignore
let th1 = Thread(ParameterizedThreadStart showThreadInformation)
th1.Start()
let th2 = Thread(ParameterizedThreadStart showThreadInformation)
th2.IsBackground <- true
th2.Start()
Thread.Sleep 500
showThreadInformation ()

// The example displays output like the following:
//       Managed thread #6:
//          Background thread: True
//          Thread pool thread: False
//          Priority: Normal
//          Culture: en-US
//          UI culture: en-US
//
//       Managed thread #3:
//          Background thread: True
//          Thread pool thread: True
//          Priority: Normal
//          Culture: en-US
//          UI culture: en-US
//
//       Managed thread #4:
//          Background thread: False
//          Thread pool thread: False
//          Priority: Normal
//          Culture: en-US
//          UI culture: en-US
//
//       Managed thread #1:
//          Background thread: False
//          Thread pool thread: False
//          Priority: Normal
//          Culture: en-US
//          UI culture: en-US
Imports System.Threading

Module Example2
    Private lock As New Object()

    Public Sub Main()
        ThreadPool.QueueUserWorkItem(AddressOf ShowThreadInformation)
        Dim th1 As New Thread(AddressOf ShowThreadInformation)
        th1.Start()
        Dim th2 As New Thread(AddressOf ShowThreadInformation)
        th2.IsBackground = True
        th2.Start()
        Thread.Sleep(500)
        ShowThreadInformation(Nothing)
    End Sub

    Private Sub ShowThreadInformation(state As Object)
        SyncLock lock
            Dim th As Thread = Thread.CurrentThread
            Console.WriteLine("Managed thread #{0}: ", th.ManagedThreadId)
            Console.WriteLine("   Background thread: {0}", th.IsBackground)
            Console.WriteLine("   Thread pool thread: {0}", th.IsThreadPoolThread)
            Console.WriteLine("   Priority: {0}", th.Priority)
            Console.WriteLine("   Culture: {0}", th.CurrentCulture.Name)
            Console.WriteLine("   UI culture: {0}", th.CurrentUICulture.Name)
            Console.WriteLine()
        End SyncLock
    End Sub
End Module
' The example displays output like the following:
'       ' Managed thread #6:
'          Background thread: True
'          Thread pool thread: False
'          Priority: Normal
'          Culture: en-US
'          UI culture: en-US
'       
'       Managed thread #3:
'          Background thread: True
'          Thread pool thread: True
'          Priority: Normal
'          Culture: en-US
'          UI culture: en-US
'       
'       Managed thread #4:
'          Background thread: False
'          Thread pool thread: False
'          Priority: Normal
'          Culture: en-US
'          UI culture: en-US
'       
'       Managed thread #1:
'          Background thread: False
'          Thread pool thread: False
'          Priority: Normal
'          Culture: en-US
'          UI culture: en-US

Передний план и фоновые потоки

Экземпляры класса Thread представляют собой потоки выполнения или фоновые потоки. Фоновые потоки идентичны потокам переднего плана с одним исключением: фоновый поток не выполняет процесс, если все потоки переднего плана завершаются. После остановки всех потоков переднего плана среда выполнения останавливает все фоновые потоки и завершает работу.

По умолчанию следующие потоки выполняются на переднем плане:

  • Основной поток выполнения приложения.

  • Все потоки, созданные путем вызова конструктора Thread класса.

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

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

    Замечание

    Асинхронные задачно-ориентированные операции автоматически выполняются в потоках пула. Асинхронные операции на основе задач используют Task и Task<TResult> классы для реализации асинхронного шаблона на основе задач.

  • Все потоки, которые входят в управляемую среду выполнения из неуправляемого кода.

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

В следующем примере показано различие между потоками переднего плана и фоновыми потоками. Это как первый пример в разделе "Пуск потока ", за исключением того, что он задает поток для выполнения в фоновом режиме перед запуском. Как показано в выходных данных, цикл прерывается до его выполнения в течение пяти секунд.

using System;
using System.Diagnostics;
using System.Threading;

public class Example
{
   public static void Main()
   {
      var th = new Thread(ExecuteInForeground);
      th.IsBackground = true;
      th.Start();
      Thread.Sleep(1000);
      Console.WriteLine($"Main thread ({Thread.CurrentThread.ManagedThreadId}) exiting...");
   }

   private static void ExecuteInForeground()
   {
      var sw = Stopwatch.StartNew();
      Console.WriteLine("Thread {0}: {1}, Priority {2}",
                        Thread.CurrentThread.ManagedThreadId,
                        Thread.CurrentThread.ThreadState,
                        Thread.CurrentThread.Priority);
      do {
         Console.WriteLine($"Thread {Thread.CurrentThread.ManagedThreadId}: Elapsed {sw.ElapsedMilliseconds / 1000.0:N2} seconds");
         Thread.Sleep(500);
      } while (sw.ElapsedMilliseconds <= 5000);
      sw.Stop();
   }
}
// The example displays output like the following:
//       Thread 3: Background, Priority Normal
//       Thread 3: Elapsed 0.00 seconds
//       Thread 3: Elapsed 0.51 seconds
//       Main thread (1) exiting...
open System.Diagnostics
open System.Threading

let executeInForeground () =
    let sw = Stopwatch.StartNew()
    printfn $"Thread {Thread.CurrentThread.ManagedThreadId}: {Thread.CurrentThread.ThreadState}, Priority {Thread.CurrentThread.Priority}"
    while sw.ElapsedMilliseconds <= 5000 do
        printfn $"Thread {Thread.CurrentThread.ManagedThreadId}: Elapsed {sw.ElapsedMilliseconds / 1000L:N2} seconds"
        Thread.Sleep 500
    sw.Stop()

let th = Thread executeInForeground
th.IsBackground <- true
th.Start()
Thread.Sleep 1000
printfn $"Main thread ({Thread.CurrentThread.ManagedThreadId}) exiting..."

// The example displays output like the following:
//       Thread 3: Background, Priority Normal
//       Thread 3: Elapsed 0.00 seconds
//       Thread 3: Elapsed 0.51 seconds
//       Main thread (1) exiting...
Imports System.Diagnostics
Imports System.Threading

Module Example1
    Public Sub Main()
        Dim th As New Thread(AddressOf ExecuteInForeground)
        th.IsBackground = True
        th.Start()
        Thread.Sleep(1000)
        Console.WriteLine("Main thread ({0}) exiting...", Thread.CurrentThread.ManagedThreadId)
    End Sub

    Private Sub ExecuteInForeground()
        Dim start As DateTime = DateTime.Now
        Dim sw As Stopwatch = Stopwatch.StartNew()
        Console.WriteLine("Thread {0}: {1}, Priority {2}",
                        Thread.CurrentThread.ManagedThreadId,
                        Thread.CurrentThread.ThreadState,
                        Thread.CurrentThread.Priority)
        Do
            Console.WriteLine("Thread {0}: Elapsed {1:N2} seconds",
                           Thread.CurrentThread.ManagedThreadId,
                           sw.ElapsedMilliseconds / 1000)
            Thread.Sleep(500)
        Loop While sw.ElapsedMilliseconds <= 5000
        sw.Stop()
    End Sub
End Module
' The example displays output like the following:
'       Thread 3: Background, Priority Normal
'       Thread 3: Elapsed 0.00 seconds
'       Thread 3: Elapsed 0.51 seconds
'       Main thread (1) exiting...

Культура и потоки

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

Это важно

Свойства CurrentCulture и CurrentUICulture работают ненадежно при использовании с любым потоком, кроме текущего потока. В .NET Framework чтение этих свойств является надёжным, хотя установка этих свойств для потока, отличного от текущего, не является надёжной. В .NET Core возникает исключение InvalidOperationException, если поток пытается считывать или записывать эти свойства из другого потока. Мы рекомендуем использовать свойства CultureInfo.CurrentCulture и CultureInfo.CurrentUICulture для получения и задания текущей культуры.

При создании экземпляра нового потока его культура и культура пользовательского интерфейса определяются текущими системными культурой и культурой пользовательского интерфейса, а не культурой и культурой пользовательского интерфейса потока, из которого создается новый поток. Это означает, например, что если текущий язык и региональные параметры системы являются английским (США) и текущим языком и региональными параметрами основного потока приложения является французский (Франция), язык и региональные параметры нового потока, созданного путем вызова Thread(ParameterizedThreadStart) конструктора из первичного потока, являются английскими (США), а не французскими (Франция). Дополнительные сведения см. в разделе "Культура и потоки" темы класса CultureInfo.

Это важно

Это не верно для потоков, выполняющих асинхронные операции для приложений, предназначенных для .NET Framework 4.6 и более поздних версий. В этом случае культура и культура пользовательского интерфейса являются частью контекста асинхронной операции; поток, на котором по умолчанию выполняется асинхронная операция, наследует культуру и культуру пользовательского интерфейса потока, запускавшего асинхронную операцию. Для получения дополнительной информации см. раздел примечаний класса CultureInfo "Региональные параметры и асинхронные операции на основе задач".

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

  • Можно передать объект, представляющий культуру, делегату CultureInfo или методу ParameterizedThreadStart.

  • Для приложений, работающих на .NET Framework 4.5 и более поздних версиях, вы можете определить языковую культуру и культуру пользовательского интерфейса, которые будут назначены всем потокам, созданным в домене приложения, задав значения для свойств CultureInfo.DefaultThreadCurrentCulture и CultureInfo.DefaultThreadCurrentUICulture. Обратите внимание, что это параметр домена для каждого приложения.

Дополнительные сведения и примеры см. в разделе CultureInfo "Культура и потоки" примечаний класса.

Получить информацию о потоках и управлять ими

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

  • Имя. Name — это свойство только для записи, которое можно использовать для идентификации потока. Значение по умолчанию — null.

  • Хэш-код, который можно получить путем вызова GetHashCode метода. Хэш-код можно использовать для уникальной идентификации потока; в течение всего времени существования потока его хэш-код не будет сталкиваться со значением из любого другого потока независимо от домена приложения, из которого вы получаете значение.

  • Идентификатор потока. Значение свойства ManagedThreadId, доступного только для чтения, назначается средой выполнения и однозначно идентифицирует поток в процессе, к которому он принадлежит.

    Замечание

    ThreadId операционной системы не имеет фиксированной связи с управляемым потоком, так как неуправляемый хост может управлять связью между управляемыми и неуправляемыми потоками. В частности, сложный хост может использовать API хостинга CLR для планирования множества управляемых потоков для одного потока операционной системы или перемещения управляемого потока между различными потоками операционной системы.

  • Текущее состояние потока. В течение всего периода своего существования поток находится в одном или нескольких состояниях, определенных свойством ThreadState.

  • Уровень приоритета планирования, определенный свойством ThreadPriority . Хотя это значение можно установить для запроса приоритета потока, операционная система не гарантирует его соблюдение.

  • Свойство только для IsThreadPoolThread чтения, указывающее, является ли поток потоком пула потоков.

  • Свойство IsBackground. Дополнительные сведения см. в разделе "Передний план" и "Фоновые потоки ".

Примеры

В следующем примере показана простая функция потоков.

using System;
using System.Threading;

// Simple threading scenario:  Start a static method running
// on a second thread.
public class ThreadExample {
    // The ThreadProc method is called when the thread starts.
    // It loops ten times, writing to the console and yielding
    // the rest of its time slice each time, and then ends.
    public static void ThreadProc() {
        for (int i = 0; i < 10; i++) {
            Console.WriteLine($"ThreadProc: {i}");
            // Yield the rest of the time slice.
            Thread.Sleep(0);
        }
    }

    public static void Main() {
        Console.WriteLine("Main thread: Start a second thread.");
        // The constructor for the Thread class requires a ThreadStart
        // delegate that represents the method to be executed on the
        // thread.  C# simplifies the creation of this delegate.
        Thread t = new Thread(new ThreadStart(ThreadProc));

        // Start ThreadProc.  Note that on a uniprocessor, the new
        // thread does not get any processor time until the main thread
        // is preempted or yields.  Uncomment the Thread.Sleep that
        // follows t.Start() to see the difference.
        t.Start();
        //Thread.Sleep(0);

        for (int i = 0; i < 4; i++) {
            Console.WriteLine("Main thread: Do some work.");
            Thread.Sleep(0);
        }

        Console.WriteLine("Main thread: Call Join(), to wait until ThreadProc ends.");
        t.Join();
        Console.WriteLine("Main thread: ThreadProc.Join has returned.  Press Enter to end program.");
        Console.ReadLine();
    }
}
open System.Threading

// Simple threading scenario:  Start a static method running
// on a second thread.

// The ThreadProc method is called when the thread starts.
// It loops ten times, writing to the console and yielding
// the rest of its time slice each time, and then ends.
let threadProc () =
    for i = 0 to 9 do
        printfn $"ThreadProc: {i}"
        // Yield the rest of the time slice.
        Thread.Sleep 0

printfn "Main thread: Start a second thread."
// The constructor for the Thread class requires a ThreadStart
// delegate that represents the method to be executed on the
// thread. F# simplifies the creation of this delegate.
let t = Thread threadProc

// Start ThreadProc.  Note that on a uniprocessor, the new
// thread does not get any processor time until the main thread
// is preempted or yields.  Uncomment the Thread.Sleep that
// follows t.Start() to see the difference.
t.Start()
//Thread.Sleep 0

for _ = 0 to 3 do
    printfn "Main thread: Do some work."
    Thread.Sleep 0

printfn "Main thread: Call Join(), to wait until ThreadProc ends."
t.Join()
printfn "Main thread: ThreadProc.Join has returned.  Press Enter to end program."
stdin.ReadLine() |> ignore
Imports System.Threading

' Simple threading scenario:  Start a Shared method running
' on a second thread.
Public Class ThreadExample
    ' The ThreadProc method is called when the thread starts.
    ' It loops ten times, writing to the console and yielding 
    ' the rest of its time slice each time, and then ends.
    Public Shared Sub ThreadProc()
        Dim i As Integer
        For i = 0 To 9
            Console.WriteLine("ThreadProc: {0}", i)
            ' Yield the rest of the time slice.
            Thread.Sleep(0)
        Next
    End Sub

    Public Shared Sub Main()
        Console.WriteLine("Main thread: Start a second thread.")
        ' The constructor for the Thread class requires a ThreadStart 
        ' delegate.  The Visual Basic AddressOf operator creates this
        ' delegate for you.
        Dim t As New Thread(AddressOf ThreadProc)

        ' Start ThreadProc.  Note that on a uniprocessor, the new 
        ' thread does not get any processor time until the main thread 
        ' is preempted or yields.  Uncomment the Thread.Sleep that 
        ' follows t.Start() to see the difference.
        t.Start()
        'Thread.Sleep(0)

        Dim i As Integer
        For i = 1 To 4
            Console.WriteLine("Main thread: Do some work.")
            Thread.Sleep(0)
        Next

        Console.WriteLine("Main thread: Call Join(), to wait until ThreadProc ends.")
        t.Join()
        Console.WriteLine("Main thread: ThreadProc.Join has returned.  Press Enter to end program.")
        Console.ReadLine()
    End Sub
End Class

Этот код создает выходные данные, аналогичные следующему:

[VB, C++, C#]
Main thread: Start a second thread.
Main thread: Do some work.
ThreadProc: 0
Main thread: Do some work.
ThreadProc: 1
Main thread: Do some work.
ThreadProc: 2
Main thread: Do some work.
ThreadProc: 3
Main thread: Call Join(), to wait until ThreadProc ends.
ThreadProc: 4
ThreadProc: 5
ThreadProc: 6
ThreadProc: 7
ThreadProc: 8
ThreadProc: 9
Main thread: ThreadProc.Join has returned. Press Enter to end program.