线程被定义为程序的执行路径。每个线程都定义了一个独特的控制流程。如果应用程序涉及复杂和耗时的操作,那么设置不同的执行路径或线程通常有助于每个线程执行特定的作业。
线程是轻量级的进程。使用线程的一个常见示例是通过现代操作系统实现并发编程。使用线程节省了CPU周期并提高了应用程序的效率。
到目前为止,我们编写了单个线程作为单个进程运行的程序,它是应用程序的运行实例。 但是,这样应用程序可以一次执行一个作业。为了使它一次执行多个任务,它可以分为较小的线程。
线程生命周期
当创建System.Threading.Thread
类的对象时,线程的生命周期将会启动,当线程终止或完成执行时,该循环将结束。
以下是线程生命周期中的各种状态:
- 未开始状态:线程实例创建但不调用
Start
方法的情况。 - 就绪状态:线程准备运行并等待CPU周期时的情况。
- 不可运行状态:线程不可执行,有以下几种情况:
Sleep
方法已被调用Wait
方法已被调用- 被I/O操作阻止
- 死亡状态:线程完成执行或中止时的情况。
主线程
在 C# 中,System.Threading.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 | 获取或设置当前线程的文化(culture)。 |
CurrentPrinciple | 获取或设置线程的当前主体(用于基于角色的安全性)。 |
CurrentThread | 获取当前正在运行的线程。 |
CurrentUICulture | 获取或设置资源管理器使用的当前文化(culture),以便在运行时查找特定于文化的资源。 |
ExecutionContext | 获取一个ExecutionContext 对象,该对象包含有关当前线程的各种上下文的信息。 |
IsAlive | 获取指示当前线程的执行状态的值。 |
IsBackground | 获取或设置一个值,指示线程是否是后台线程。 |
IsThreadPoolThread | 获取一个值,指示线程是否属于托管线程池。 |
ManagedThreadId | 获取当前受管线程的唯一标识符。 |
Name | 获取或设置线程的名称。 |
Priority | 获取或设置一个指示线程的调度优先级的值。 |
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() |
取消当前线程中止请求。 |
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 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) |
立即将值写入字段,以便该值对计算机中的所有处理器可见。此方法具有不同的重载形式。上面只给出了几个。 |
23 | 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")
// the thread is paused for 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("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
块(如果有的话)。
以下一个实现线程的程序:
using System
using System.Threading
namespace MultithreadingApplication
{
class ThreadCreationProgram
{
public static void CallToChildThread()
{
try
{
Console.WriteLine("Child thread starts")
// do some work, like counting to 10
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&apost 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()
//stop the main thread for some time
Thread.Sleep(2000)
//now abort the child
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&apost catch the Thread Exception