首页 > 代码库 > C#线程
C#线程
进程和线程
进程是一个系统级别的概念,用来描述一组资源和程序运行所必须的内存分配。每一个进程都有一个唯一的进程标识符(PID);线程是进程的基本单元;进程的入口点创建的第一个线程被称为主线程;线程主要是由CPU寄存器、调用栈和线程本地存储器(Thread Local Storage,TLS)组成的。CPU寄存器主要记录当前所执行线程的状态,调用栈主要用于维护线程所调用到的内存与数据,TLS主要用于存放线程的状态信息。
应用程序域(AppDomain):.Net可执行程序承载在进程中的逻辑分区;一个进程可以包含多个应用程序域,每一个应用程序域中承载一个.Net可执行程序;每一个程序域都和该进程(或其它进程)中的其它的程序域完全彻底隔离开,只有使用分布式编程协议(如WCF)才能访问其它应用程序域中的任何数据;
System.AppDomain
一个线程可以穿梭在多个应用程序域中,但在某个时刻,线程只会处于一个应用程序域内。
上下文边界
每个线程都有自己的属性,在每个线程的内核对象之中,都包含一个上下文结构,上下文结构的存在是为了反映在线程上一次执行时,线程CPU寄存器的状态。在任何时刻,Windows只将一个线程代码分配给一个CPU,一个线程允许运行一个时间片,在线程的“时间片”结束之后,Windows会检查现有所有线程内核对象,只有那些没有在等待什么的线程才适合调度。Windows选择一个可调度的线程内核对象,并且换到它。
Windows选择一个可调度的线程有一套独特的标准,Windows执行线程的规律和时间片没多大的关系,线程在运行的任何时刻都可以停止,然后Windows又去调度另一个线程,你有点控制权,去控制你想运行的线程,但是这控制权不多,不控制为好。对于线程的执行,记住一点:
你不能保证自己的线程一直运行,你不能阻止其他的线程的运行。
线程优先级别0~31,Windows把线程用从高到低的调度方式轮流调度线程,假如有一个优先级别为31的线程运行结束了,然后Windows会找下一个空闲的线程,如果空闲的线程中有一个级别也是31的线程,那么Windows又会把31级别的线程交给CPU处理。
进程优先级类:
Windows支持6个进程优先级类:Idel,Below Normal,Normal,Above Normal,Hight和Realtime(依次向高),其中Normal是默认的进程优先级,所以它是最常用的。
Windows支持7个相对线程优先级:Idel,Lowest,Below Normal,Normal,Above Normal,Highest和Time-Critical。
相对线程优先级 |
进程优先级 |
|
||||
Idle |
Below Normal |
Normal |
Above Normal |
High |
Realtime |
|
Time-critical |
15 |
15 |
15 |
15 |
15 |
31 |
Highest |
6 |
8 |
10 |
12 |
15 |
26 |
Above Normal |
5 |
7 |
9 |
11 |
14 |
25 |
Normal |
4 |
6 |
8 |
10 |
13 |
24 |
Below Normal |
3 |
5 |
7 |
9 |
12 |
23 |
Lowest |
2 |
4 |
6 |
8 |
11 |
22 |
Idle |
1 |
1 |
1 |
1 |
1 |
16 |
记住:如果更改一个进程的优先级类,线程的相对优先级不会改变,但它的优先值会改变。
Windows永远都不会调度进程,他调度的只有线程,“进程优先级类”是Microsoft提出的一个抽象概念,目的是为了帮助你理解自己的应用程序和其他正在运行的应用程序的关系,它没有别的用途。
可以更改它的线程相对优先级,Thread中的Priority属性,向它传递ThreadPriority枚举类型中定义的5各值之一,即在上表中的灰色部分列。
线程池ThreadPool
每个进程都有一个线程池,线程池的默认大小为:每个可用的处理器有 25 个线程。使用 SetMaxThreads 方法可以更改线程池中的线程数。
ThreadPool类型拥有一个QueueUserWorkItem的静态方法。该静态方法接收一个委托(WaitCallback),代表用户自定义的一个异步操作。
// 一个 System.Threading.WaitCallback,表示要执行的方法。
// 如果此方法成功排队,则为 true;如果未能将该工作项排队,则引发 System.NotSupportedException。
//System.NotSupportedException:承载公共语言运行时的宿主不支持此操作。
[SecuritySafeCritical]
public static bool QueueUserWorkItem(WaitCallback callBack); // 将方法排入队列以便执行,并指定包含该方法所用数据的对象。此方法在有线程池线程变得可用时执行。
// System.Threading.WaitCallback,它表示要执行的方法。
// state: 包含方法所用数据的对象。
// 如果此方法成功排队,则为 true;如果未能将该工作项排队,则引发 System.NotSupportedException。
[SecuritySafeCritical]
public static bool QueueUserWorkItem(WaitCallback callBack, object state);
使用线程池的好处:
减少了线程的创建、开始和停止的次数,提高了效率
能够使我们将注意力放在业务逻辑上而不是多线程架构上。
以下场景是不适合使用线程池,而是手工管理线程:
- 需要前台线程时。因为线程池中的线程总是后台线程。
- 需要线程具有特定的优先级。因为放到线程池中的线程都是默认的优先级(ThreadPriority.Normal),无法对其优先级进行设置。
- 需要长时间运行的任务。由于线程池具有最大线程数限制,因此大量阻塞的线程池线程可能会阻止任务启动。
- 如果需要有一个带有固定标识的线程便于退出、挂起或通过名字发现它。
- 对于COM对象,入池的所有线程都是多线程单元(multithreaded apartment MTA)线程;许多COM对象都需要单线程单元(single-threaded apartment STA)线程;
C#线程