线程
线程被定义为程序的执行路径。每个线程定义了一个独特的控制流。如果你的应用涉及到复杂且耗时的操作,那么设置不同的执行路径或线程,每个线程执行一个特定的任务,通常是很有帮助的。
线程是轻量级的进程。现代操作系统中使用线程的一个常见例子是并发编程的实现。使用线程节省了CPU周期的浪费并提高了应用程序的效率。
到目前为止,我们编写的程序都是单线程运行作为一个单一的进程,这是应用程序的运行实例。但是,这种方式下应用一次只能执行一个任务。为了使它能够同时执行多个任务,它可以被分解成更小的线程。
线程生命周期
线程的生命周期从创建 System.Threading.Thread
类的一个实例开始,并在线程终止或完成执行时结束。
以下是线程生命周期中的各种状态:
-
未启动状态 - 这是创建线程实例但尚未调用
Start
方法的情况。
-
就绪状态 - 这是线程准备好运行并在等待CPU周期的情况。
-
不可运行状态 - 当线程处于以下情况之一时,它是不可执行的:
-
主线程
在C#中,System.Threading.Thread
类用于处理线程。它允许在一个多线程应用程序中创建和访问独立的线程。进程中的第一个被执行的线程称为主线程。
当一个C#程序开始执行时,主线程会自动创建。使用 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 获取或设置当前线程的文化信息。
-
CurrentPrinciple 获取或设置线程的当前主要身份(用于基于角色的安全性)。
-
CurrentThread 获取当前正在运行的线程。
-
CurrentUICulture 获取或设置资源管理器在运行时查找文化特定资源时使用的当前文化。
-
ExecutionContext 获取包含当前线程的各种上下文信息的 ExecutionContext
对象。
-
IsAlive 获取一个指示当前线程执行状态的值。
-
IsBackground 获取或设置一个值,指示线程是否为后台线程。
-
IsThreadPoolThread 获取一个值,指示线程是否属于托管线程池。
-
ManagedThreadId 获取当前托管线程的唯一标识符。
-
-
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() 使调用线程将执行权让给当前处理器上准备运行的另一个线程。操作系统选择出让执行权的线程。
创建线程
线程是通过扩展 Thread 类来创建的。扩展后的 Thread 类然后调用 Start() 方法来开始子线程的执行。
下面的程序演示了这一概念:
using 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() 方法来使线程暂停特定的时间段。
using 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 来中止线程。这个异常无法被捕获,控制权会被发送到最终块(如果有的话)。
下面的程序说明了这一点:
using 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