C# 多线程

多线程是多个线程同时工作的过程。您可以将线程视为程序的执行路径。每个线程定义自己的控制流来完成特定任务。如果您的应用程序涉及复杂且耗时的操作,那么使用多个线程来执行这些操作可能会有所帮助。多线程可以节省CPU资源并使您的应用程序运行更高效。例如,现代操作系统中并发编程的实现使用多线程。到目前为止,我们创建的示例程序是一次执行一项任务的单线程应用程序。

线程生命周期

线程的生命周期从创建 System.Threading.Thread 类对象时开始,到线程终止或完成执行时结束。 线程生命周期的各种状态如下所示。

  • 未启动状态:线程实例创建完成但Start方法尚未调用时的状态。
  • 就绪状态:线程已准备好运行并等待 CPU 周期的状态。
  • 不可执行状态:线程在以下情况下不能运行:
    • Sleep 方法正在被调用。
    • 正在调用等待方法。
    • 由于 I/O 操作而阻塞。
  • 死亡状态:线程已完成执行或已中止的状态。

主线程

C# 使用 System.Threading.Thread 类来处理线程。这允许多线程应用程序创建和访问单独的线程。多线程运行的第一个线程称为主线程。当C#程序开始运行时,会自动创建一个主线程,使用Thread类创建的线程称为子线程。用于访问线程的线程类。下面显示了运行主线程的示例程序。

 use System;
use System.Threading;

namespace it-kiso.com
{
    クラス Demo
    {
        static void Main(string[] args)
        {
            Thread th = Thread.CurrentThread;
            th.Name = "Thread Name";
            Console.WriteLine("これは{0}です", th.Name);
            Console.ReadKey();
        }
    }
} 

操作的结果将是:

これはThread Nameです

Thread类的属性和方法

下表列出了 Thread 类的一些常用属性。

属性 解释
CurrentContext 获取线程运行的上下文
CurrentCulture 获取或设置当前线程的区域性
CurrentPrincipal 获取或设置线程的当前领导者(用于基于角色的安全性)
CurrentThread 获取当前正在运行的线程
CurrentUICulture 获取或设置资源管理器使用的当前区域性,以在运行时查找特定于区域性的资源
ExecutionContext 获取一个 ExecutionContext 对象,该对象包含有关当前线程的各种上下文的信息。
IsAlive 获取当前线程的执行状态
IsBackground 获取或设置一个值,该值指示线程是否为后台线程
IsThreadPoolThread 获取线程是否属于托管线程池
ManagedThreadId 获取当前托管线程的唯一标识符
Name 获取或设置线程的名称
Priority 获取或设置线程的调度优先级
ThreadState 获取当前线程状态

下表列出了Thread类的一些常用方法。

方法名称 解释
public void Abort() 通过在调用此方法的线程上抛出 ThreadAbortException 来终止此线程
public static LocalDataStoreSlot AllocateDataSlot() 将未命名的数据槽分配给所有线程。为了获得更好的性能,请改用标有 ThreadStaticAttribute 属性的字段。
public static LocalDataStoreSlot AllocateNamedDataSlot(string name) 将命名数据槽分配给所有线程。为了获得更好的性能,请改用标有 ThreadStaticAttribute 属性的字段。
public static void BeginCriticalRegion() 通知主机执行即将继续到应用程序域中的其他任务可能由于线程中止或未处理的异常而面临风险的代码区域。
public static void BeginThreadAffinity() 通知主机托管代码即将执行依赖于当前物理操作系统线程的特定指令。
public static void EndCriticalRegion() 通知主机执行即将继续到线程中止或未处理的异常仅影响当前任务的代码区域。
public static void EndThreadAffinity() 通知主机托管代码已完成执行依赖于当前物理操作系统线程的某些指令。
public static void FreeNamedDataSlot(string name) 将名称与进程中所有线程的数据槽解除关联。为了获得更好的性能,请改用标有 ThreadStaticAttribute 属性的字段。
public static Object GetData(LocalDataStoreSlot slot) 获取当前线程中指定的值。为了获得更好的性能,请改用标有 ThreadStaticAttribute 属性的字段。
public static AppDomain GetDomain() 返回当前线程正在运行的域。
public static AppDomain GetDomainID() 返回应用程序域的唯一标识符。
public static LocalDataStoreSlot GetNamedDataSlot(string name) 找到指定的数据槽。为了获得更好的性能,请改用标有 ThreadStaticAttribute 属性的字段。
public void Interrupt() 挂起处于 WaitSleepJoin 状态的线程
public void Join() 标准 COM 和 SendMessage 会阻塞调用线程,直至其终止,同时消息泵继续进行。该方法有多种重载形式
public static void MemoryBarrier() 同步内存访问如下:运行当前线程的处理器无法通过首先在 MemoryBarrier 调用之后执行内存访问,然后在 MemoryBarrier 调用之前执行内存访问来重新排序指令。
public static void ResetAbort() 取消当前线程请求的中止。
public static void SetData(LocalDataStoreSlot slot, Object data) 在当前正在运行的线程的当前域中的指定槽中设置数据。为了获得更好的性能,请改用标有 ThreadStaticAttribute 属性的字段。
public void Start() 启动一个线程
public static void Sleep(int millisecondsTimeout) 将线程挂起一段时间
public static void SpinWait(int iterations) 使线程等待一段时间。时间长度由迭代参数定义。
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)
读取字段值。该值是计算机处理器写入的最新值,无论处理器的数量或处理器缓存的状态如何。
public 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)
立即将值写入字段并使该值对计算机中的所有处理器可见。
public static bool Yield() 终止当前调用的线程并运行另一个准备运行的线程(操作系统选择执行的另一个线程)。

创建一个线程

C# 扩展了 Thread 类来创建线程,并使用扩展的 Thread 类调用 Start() 方法来开始执行子线程。下面通过一个示例程序展示了线程的创建。

 using System;
using System.Threading;

namespace it-kiso.com
{
    class Demo
    {
        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関数で子スレッドを作成します
子スレッドが実行されています

管理线程

Thread 类提供了各种管理线程的方法。例如,您可以使用 sleep() 方法将线程挂起特定时间段,如下例所示。

 using System;
using System.Threading;

namespace it-kiso.com
{
    class Demo
    {
        public static void CallToChildThread()
        {
            Console.WriteLine("サブスレッドを実行します。");
            // スレッドを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("メイン関数でサブスレッドを作成します。");
            Thread childThread = new Thread(childref);
            childThread.Start();
            Console.ReadKey();
        }
    }
} 

销毁线程

Thread 类提供了 Abort() 方法来销毁线程。 Abort() 方法抛出一个 threadabortException 异常来终止线程。此异常是无法捕获的,如以下示例所示。

 using System;
using System.Threading;

namespace it-kiso.com
{
    class Demo
    {
        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("スレッド中断:{0}", e);
            }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();
        }
    }
} 
多线程是多个线程同时工作的过程。您可以将线程视为程序的执行路径。每个线程定义自己的控制流来完成特定任务。如果您的应用程序涉及复杂且耗时的操作,那么使用多个线程来执行这些操作可能会有所帮助。多线程可以节省CPU资源并使您的应用程序运行更高效。例如,现代操作系统中并发编程的实现使用多线程。到目前为止,我们创建的示例程序是一次执行一项任务的单线程应用程序。

线程生命周期

线程的生命周期从创建 System.Threading.Thread 类对象时开始,到线程终止或完成执行时结束。 线程生命周期的各种状态如下所示。

  • 未启动状态:线程实例创建完成但Start方法尚未调用时的状态。
  • 就绪状态:线程已准备好运行并等待 CPU 周期的状态。
  • 不可执行状态:线程在以下情况下不能运行:
    • Sleep 方法正在被调用。
    • 正在调用等待方法。
    • 由于 I/O 操作而阻塞。
  • 死亡状态:线程已完成执行或已中止的状态。

主线程

C# 使用 System.Threading.Thread 类来处理线程。这允许多线程应用程序创建和访问单独的线程。多线程运行的第一个线程称为主线程。当C#程序开始运行时,会自动创建一个主线程,使用Thread类创建的线程称为子线程。用于访问线程的线程类。下面显示了运行主线程的示例程序。

 use System;
use System.Threading;

namespace it-kiso.com
{
    クラス Demo
    {
        static void Main(string[] args)
        {
            Thread th = Thread.CurrentThread;
            th.Name = "Thread Name";
            Console.WriteLine("これは{0}です", th.Name);
            Console.ReadKey();
        }
    }
} 

操作的结果将是:

これはThread Nameです

Thread类的属性和方法

下表列出了 Thread 类的一些常用属性。

属性 解释
CurrentContext 获取线程运行的上下文
CurrentCulture 获取或设置当前线程的区域性
CurrentPrincipal 获取或设置线程的当前领导者(用于基于角色的安全性)
CurrentThread 获取当前正在运行的线程
CurrentUICulture 获取或设置资源管理器使用的当前区域性,以在运行时查找特定于区域性的资源
ExecutionContext 获取一个 ExecutionContext 对象,该对象包含有关当前线程的各种上下文的信息。
IsAlive 获取当前线程的执行状态
IsBackground 获取或设置一个值,该值指示线程是否为后台线程
IsThreadPoolThread 获取线程是否属于托管线程池
ManagedThreadId 获取当前托管线程的唯一标识符
Name 获取或设置线程的名称
Priority 获取或设置线程的调度优先级
ThreadState 获取当前线程状态

下表列出了Thread类的一些常用方法。

方法名称 解释
public void Abort() 通过在调用此方法的线程上抛出 ThreadAbortException 来终止此线程
public static LocalDataStoreSlot AllocateDataSlot() 将未命名的数据槽分配给所有线程。为了获得更好的性能,请改用标有 ThreadStaticAttribute 属性的字段。
public static LocalDataStoreSlot AllocateNamedDataSlot(string name) 将命名数据槽分配给所有线程。为了获得更好的性能,请改用标有 ThreadStaticAttribute 属性的字段。
public static void BeginCriticalRegion() 通知主机执行即将继续到应用程序域中的其他任务可能由于线程中止或未处理的异常而面临风险的代码区域。
public static void BeginThreadAffinity() 通知主机托管代码即将执行依赖于当前物理操作系统线程的特定指令。
public static void EndCriticalRegion() 通知主机执行即将继续到线程中止或未处理的异常仅影响当前任务的代码区域。
public static void EndThreadAffinity() 通知主机托管代码已完成执行依赖于当前物理操作系统线程的某些指令。
public static void FreeNamedDataSlot(string name) 将名称与进程中所有线程的数据槽解除关联。为了获得更好的性能,请改用标有 ThreadStaticAttribute 属性的字段。
public static Object GetData(LocalDataStoreSlot slot) 获取当前线程中指定的值。为了获得更好的性能,请改用标有 ThreadStaticAttribute 属性的字段。
public static AppDomain GetDomain() 返回当前线程正在运行的域。
public static AppDomain GetDomainID() 返回应用程序域的唯一标识符。
public static LocalDataStoreSlot GetNamedDataSlot(string name) 找到指定的数据槽。为了获得更好的性能,请改用标有 ThreadStaticAttribute 属性的字段。
public void Interrupt() 挂起处于 WaitSleepJoin 状态的线程
public void Join() 标准 COM 和 SendMessage 会阻塞调用线程,直至其终止,同时消息泵继续进行。该方法有多种重载形式
public static void MemoryBarrier() 同步内存访问如下:运行当前线程的处理器无法通过首先在 MemoryBarrier 调用之后执行内存访问,然后在 MemoryBarrier 调用之前执行内存访问来重新排序指令。
public static void ResetAbort() 取消当前线程请求的中止。
public static void SetData(LocalDataStoreSlot slot, Object data) 在当前正在运行的线程的当前域中的指定槽中设置数据。为了获得更好的性能,请改用标有 ThreadStaticAttribute 属性的字段。
public void Start() 启动一个线程
public static void Sleep(int millisecondsTimeout) 将线程挂起一段时间
public static void SpinWait(int iterations) 使线程等待一段时间。时间长度由迭代参数定义。
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)
读取字段值。该值是计算机处理器写入的最新值,无论处理器的数量或处理器缓存的状态如何。
public 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)
立即将值写入字段并使该值对计算机中的所有处理器可见。
public static bool Yield() 终止当前调用的线程并运行另一个准备运行的线程(操作系统选择执行的另一个线程)。

创建一个线程

C# 扩展了 Thread 类来创建线程,并使用扩展的 Thread 类调用 Start() 方法来开始执行子线程。下面通过一个示例程序展示了线程的创建。

 using System;
using System.Threading;

namespace it-kiso.com
{
    class Demo
    {
        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関数で子スレッドを作成します
子スレッドが実行されています

管理线程

Thread 类提供了各种管理线程的方法。例如,您可以使用 sleep() 方法将线程挂起特定时间段,如下例所示。

 using System;
using System.Threading;

namespace it-kiso.com
{
    class Demo
    {
        public static void CallToChildThread()
        {
            Console.WriteLine("サブスレッドを実行します。");
            // スレッドを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("メイン関数でサブスレッドを作成します。");
            Thread childThread = new Thread(childref);
            childThread.Start();
            Console.ReadKey();
        }
    }
} 

销毁线程

Thread 类提供了 Abort() 方法来销毁线程。 Abort() 方法抛出一个 threadabortException 异常来终止线程。此异常是无法捕获的,如以下示例所示。

 using System;
using System.Threading;

namespace it-kiso.com
{
    class Demo
    {
        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("スレッド中断:{0}", e);
            }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();
        }
    }
}