C#线程处理 :一、线程基础(曹海涛)

网友投稿 287 2022-08-19

C#线程处理 :一、线程基础(曹海涛)

本笔记摘抄自:https://cnblogs.com/zhili/archive/2012/07/18/Thread.html,保存方便资料查找

一、线程的介绍

进程(Process)是应用程序的实例要使用的资源的一个集合,每个应用程序都在各自的进程中运行来确保应用程序不受其他应用程序的影响。

线程是进程中基本执行单元, 一个进程中可以包含多个线程。在进程入口执行的第一个线程是一个进程的主线程,在.NET应用程序中,都是以Main()方法

作为程序的入口(线程是进程的执行单元,进程是线程的一个容器)。

二、线程调度和优先级

Windows之所以被称为抢占式多线程操作系统,是因为线程可以在任意时间被抢占,并调度另一个线程。

每个线程都分配了从0~31的一个优先级,系统首先把高优先级的线程分配给CPU执行。

Windows 支持7个相对线程优先级:Idle、Lowest、Below Normal、Normal、Above Normal、Highest和Time-Critical。Normal是默认的线程优先级,

然而在程序中可以通过设置Thread的Priority属性来改变线程的优先级,它的类型为ThreadPriority枚举类型:Lowest、BelowNormal、Normal、AboveNormal

和Highest,CLR为自己保留了 Idle和Time-Critical优先级。

枚举值列表如下:

成员名称

说明

Lowest

可以将Thread置于其他优先级线程之后。

BelowNormal

可以将Thread置于Normal优先级线程之后Lowest优先级线程之前。

Normal

可以将Thread置于AboveNormal优先级线程之后BelowNormal优先级线程之前。

默认情况下,线程置于Normal优先级。

AboveNormal

可以将Thread置于Highest优先级线程之后Normal优先级线程之前。

Highest

可以将Thread置于其他优先级线程之前。

三、前台线程和后台线程

在.NET中线程分为前台线程和后台线程:

1、主线程是程序开始时就执行的,如果你需要再创建线程,那么创建的线程就是这个主线程的子线程,它是前台线程。

2、子线程可以是前台线程也可以是后台线程。

3、前台线程必须全部执行完,即使主线程关闭掉,这时进程仍然存活。

4、当所有前台线程停止运行时,CLR会强制结束仍在运行的任何后台线程,这些后台线程直接被终止,不会抛出异常。

5、前台线程与后台线程唯一的区别是后台线程不会阻止进程终止,可以在任何时候将前台线程修改为后台线程。

假如保留IsBackground = true;但又想继续执行Worker()方法的话,可以调用Thread.Join()方法来实现。Join()方法能保证主线程(前台线程)在异步线程

Thread(后台线程)运行结束后才会运行。

注1:一个线程在执行的过程中,可能调用另一个线程,前者可以称为调用线程,后者成为被调用线程。

注2:Thread.Join()方法的使用场景:调用线程挂起,等待被调用线程执行完毕后,继续执行。

注3:被调用线程执行Join方法,告诉调用线程,你先暂停,我执行完了,你再执行。从而保证了先后关系。

运行结果如下:

四、 Suspend和Resume方法

这两个方法在.NET Framework 1.0的时候就支持的方法,他们分别可以挂起线程及恢复挂起的线程,但在.NET Framework 2.0以后的版本中这两个方法都过时了。

MSDN的解释是这样:

警告:

不要使用Suspend和Resume方法来同步线程的活动。您无法知道挂起线程时它正在执行什么代码。如果您在安全权限评估期间挂起持有锁的线程,

则AppDomain中的其他线程可能被阻止。如果您在线程正在执行类构造函数时挂起它,则 AppDomain中尝试使用该类的其他线程将被阻止。这样很容易发生死锁。

在上面这段代码中Thread1线程是在主线程中恢复的,但当主线程发生异常时,这时候Thread1就会一直处于挂起状态,此时Thread1所使用的资源就不能释放

(除非强制终止进程),当其它的线程需要使用这快资源的时候, 很有可能就会发生死锁现象。

上面一段代码还存在一个隐患,假如把Thread.Sleep(2000);这段代码注释一下:

这个时候,主线程因为跑(运行)得太快,做完自己的事情去唤醒Thread1时,此时Thread1还没有挂起,而此时唤醒Thread1就会出现异常了。

五、Abort和Interrupt方法

Abort方法和Interrupt都是用来终止线程的,但是两者还是有区别的:

1、它们抛出的异常不一样:Abort 方法抛出的异常是ThreadAbortException,Interrupt抛出的异常为ThreadInterruptedException。

2、调用Interrupt方法的线程之后可以被唤醒,然而调用Abort方法的线程就直接被终止不能被唤醒了。

下面演示Abort方法的使用:

运行结果如下:

从运行结果可以看出,调用Abort方法的线程引发的异常类型为ThreadAbortException,另外异常只会在调用Abort方法的线程中发生,而不会在主线程中抛出,

其次调用Abort方法后线程的状态不是立即改变为Aborted状态,而是从AbortRequested->Aborted。

下面演示Interrupt方法的使用:

运行结果如下:

从结果中可以得到,调用Interrupt方法抛出的异常为:ThreadInterruptException, 另外当调用Interrupt方法后线程的状态应该是中断的,但是从运行结果看,

此时的线程因为Join、Sleep方法而唤醒了线程。

为了进一步解释调用Interrupt方法的线程可以被唤醒, 我们可以在线程执行的方法中运用循环,如果线程可以唤醒,则输出结果中就一定会有循环的部分,

而调用Abort方法的线程则不会有循环的部分。

下面代码相信大家看后肯定会更加理解两个方法的区别:

运行结果如下:

如果把上面的threadWake.Interrupt();改为threadWake.Abort(); 运行结果为:

六、简单线程的使用

其实在上面介绍前台线程和后台线程的时候已经通过ThreadStart委托创建一个线程了,此时已经实现了一个多线程的一个过程。

下面通过ParameterizedThreadStart委托的方式来实现多线程:

运行结果如下:

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:C# 读取.resx资源文件写入到json文件中(cctv5)
下一篇:双11超级工程—阿里巴巴数据库技术架构演进与阿里云技术(尽在双11:阿里巴巴技术演进与超越)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~