C# 多线程编程的基本概念

  下面的一些基本概念可能和.NET的联系并不大,但对于掌握.NET中的多线程开发来说却十分重要。我们在开始尝试多线程开发前,应该对这些基础知识有所掌握,并且能够在操作系统层面理解多线程的运行方式。

1.1 操作系统层面的进程和线程

  (1)进程

  进程代表了操作系统上运行着的一个应用程序。进程拥有自己的程序块,拥有独占的资源和数据,并且可以被操作系统调度。But,即使是同一个应用程序,当被强制启动多次时,也会被安放到不同的进程之中单独运行。

  直观地理解进程最好的方式就是通过进程管理器浏览,其中每条记录就代表了一个活动着的进程:

  (2)线程

  线程有时候也被称为轻量级进程,它的概念和进程十分相似,是一个可以被调度的单元,并且维护自己的堆栈和上下文环境。线程是附属于进程的,一个进程可以包含1个或多个线程,并且同一进程内的多个线程共享一块内存块和资源

  由此看来,一个线程是一个操作系统可调度的基本单元,但是它的调度受限于该线程所属的进程,也就是说操作系统首先决定执行下一个执行的进程,进而才会调度该进程内的线程。一个线程的基本生命周期如下图所示:

  (3)进程和线程的区别

  最大的区别在于隔离性,每个进程都会被单独隔离(进程拥有自己的内存、资源和运行数据,一个进程的崩溃不会影响到其他进程,因此进程间的交互也相对困难),而同一进程内的所有线程则共享内存和资源,并且一个线程可以访问和结束同一进程内的其他线程。

1.2 多线程程序在操作系统中是并行执行的吗?

  (1)线程的调度

  在计算机系统发展的早期,操作系统层面不存在并行的概念,所有的应用程序都在排队等候一个单线程的队列之中,每个程序都必须等到前面的程序都安全执行完毕之后才能获得执行的权利,一个小小的错误将会导致操作系统上的所有程序的阻塞。在后来的操作系统中,逐渐产生了分时和进程、线程的概念。

  多个线程由操作系统进行调度控制,决定何时运行哪个线程。所谓线程调度,是指操作系统决定如何安排线程执行顺序的算法。按常规分类,线程调度可以分为以下两种:

  ①抢占式调度

  抢占式调度是指每个线程都只有极少的运行时间(在Windows NT内核模式下这个时间不会超过20ms),而当时间片用完时该线程就会被强制暂停,保存上下文并把运行权利交给下一个线程。这样调度的结果就是:所有的线程都在被不停地快速切换运行,使得用户感觉所有的线程都在并行运行

  ②非抢占式调度

  非抢占式调度是指某个线程在运行时不会被操作系统强制暂停,它可以持续地运行直到运行告一段落并主动交出运行权。在这样的调度方式之下,线程的运行就是单队列的,并且可能产生恶意程序长期霸占运行权的情况。

PS:现在很多的操作系统(包括Windows在内),都同时采用了抢占式和非抢占式模式。对于那些优先级较高的线程,OS采用非抢占式来给予充分的时间运行,而对于普通的线程,则采用抢占式模式来快速地切换执行。

  (2)线程的并行问题

  在单核单CPU的硬件架构上,线程的并行运行完全是用户的主观体验。事实上,在任一时刻只可能存在一个处于运行状态的线程。但在多CPU或多核的架构上,情况则略有不同。多CPU多核的架构则允许系统完全并行地运行两个或多个无其他资源争用的线程,理论上这样的架构可以使运行性能整数倍地提高。

PS:微软公司曾经提出超线程技术,简单说来这是一种逻辑上模拟多CPU的技术,但实际上它们却共享物理处理器和缓存,超线程对性能的提高相当有限。

1.3 神马是纤程?

  (1)纤程的概念

  纤程是微软公司在Windows上提出的一个概念,其设计目的是用来方便地移植其他操作系统上的应用程序。一个线程可以拥有0个或多个纤程,一个纤程可以视为一个轻量级的线程,它拥有自己的栈和上下文状态。But,纤程的调度是由程序员编码控制的,当一个纤程所在线程得到运行时,程序员需要手动地决定运行哪一个纤程

PS:事实上,Windows操作系统内核是不知道纤程的存在的,它只负责调度所有的线程,而纤程之所以成为操作系统的概念,是因为Windows提供了关于线程操作的Win32函数,能够方便地帮助程序员进行线程编程。

  (2)纤程和线程的区别

  纤程和线程最大的区别在于:线程的调度受操作系统的管理,程序员无法进行完全干涉。但纤程却完全受控于程序员本身,允许程序员对多任务进行自定义的调度和控制,因此纤程带给程序员很大的灵活性。

  下图展示了进程、线程以及纤程三者之间的关系:

  (3)纤程在.NET中的地位

  需要谨记是的一点是:.NET运行框架没有做出关于线程真实性的保证!也就是说,我们在.NET程序中新建的线程并不一定是操作系统层面上产生的一个真正线程。在.NET框架寄宿的情况下,一个程序中的线程很可能对应某个纤程

PS:所谓CLR寄宿,就是指CLR运行在某个应用程序而非操作系统内。常见的寄宿例子是微软公司的SQL Server 2005。

posted @ 2020-05-29 10:44  delafqm  阅读(201)  评论(0编辑  收藏  举报