线程基础1

对多数开发者,使用多线程的主要动机就是来执行长期在后台工作一个或多个任务,而前台还能提供一个高效的可交互的用户界面的能力。另一种常见的情形(场景)是当构建C/S的服务端时,欲使服务端(Server)同时执行多个长期运行的任务,使用线程技术可使这些任务分别运行在一个独立的线程中,这样以提高服务端的可用性,IO吞吐量等指标。
*
**
         线程是一个执行单元。
         进程是一个内存分配和调度单元。
线程被称为轻量级进程,其不同之处在于内存的分配,操作系统(OS)在分配内存是按进程分配的不是按线程(相当于公司发工资可能是分给各个部门,至于往下的层级他们就不考虑了,部门内想怎么分是部门的事),多数进程仅有一个主线程(当然现在的程序多是多线程情形了),所以二者几乎特征一致。你可以这样认为:进程的就是一颗大树,其主线程是一个主干,其余的分支就是子线程。
**
***
这里介绍的多线程技术适用于任何.net语言。

当程序运行时,CPU实际在运行处理器指令的序列,一个接一个。你可认为这些指令序列是一个被CPU执行的线程。一个线程实际是一个指向组成应用程序的指令序列的当前指令序列的指针。这个指针始于程序的顶部并逐行下移,当遇到决定(if,switch等)和循环时(while,for,loop等)执行流程会出现分叉和循环。(任何一个程序都可以使用:顺序,分支,循环这三种结构搭建起来,该结论已经被数学证明了)当程序不再需要时,指针会跳出程序代码,并且程序会有效终止。

多数程序只有一个线程,所以只执行一个指令序列,另外一些程序可能有多个线程,所以可同时执行这些指令序列。必须清楚认识到(在单CPU下),任何时刻,只能有一个线程处于执行状态。所谓的同时,只不过是CPU快速的交叉执行,这种速度很快以至于使我们误以为它们是“同时”的。当然多CPU时任意一个时刻,可每个CPU可有一个线程被执行。

我们产生“同时”的幻象,是OS为我们做的。它的具体实现,多采用“分时”技术
***
****
进程。
多任务是指OS(操作系统)一次运行多个程序的情形,每个计算机内存中保持的程序作为一个进程。进程是一个隔离的内存区域,含有代码和数据。进程间代码和数据不会“串岗”的,除非你是恶意的(堆栈攻击,就是算指令或数据的位置来摧毁堆栈,或注入一些跳转到其它地方的函数的指针)。
进程起始于程序的执行,只要程序一直运行,进程就一直存在。当进程启动时,OS为其分配一块独立的内存区域并将代码加载进该区域。之后启动进程的主线程指向程序的第一条指令。之后线程运行由程序定义的指令序列。1
windows支持多线程,所有主线程可能在同一个进程中创建多个线程。所有的这些线程将共享相同的进程空间。一个进程中的线程并不互相独立,一个线程可以访问同一进程中的其他线程的数据。位于一个进程中的线程并不能访问其他进程中的线程的数据。

****
*****
.net 框架的AppDomain是一个混合进程和线程概念的东西。(关于AppDomain的详细信息请参考《Applied Microsoft .NET Framework Programming》——Jeffrey Richter 著),概念上AppDomain很像进程,每个应用程序域(AppDomain)是一个独立的内存区域,运行在一个AppDomain中的代码不可以访问其他AppDomain中的内存。.net引入AppDomain是想在同一个windows进程中运行多个独立的程序。因为创建一个Windows进程相对比较耗时和耗内存。在一个已存在的进程中创建一个应用程序域相对“便宜”些。
Windows没有应用程序域的概念,它只明白进程,使任何代码被运行的唯一手段就是将其加载到进程,这意味着应用程序域存在于进程之中,结果是.net代码总是运行在一个进程的应用程序域之中。
一个应用程序域是一组程序集的一个逻辑容器,应用程序域之间是隔离的,应用程序域可被单独卸载,应用程序域可以单独实施安全策略和配置策略。(跨应用程序域的能力,可能通过System.Serializable,he System.MarshallByRefObject名空间提供的API来实现)

线程和应用程序域之间不存在一对一的关系,当一个应用程序域中的线程调用另一个应用程序域中的方法时,线程会在两个应用程序域间跳转,这意味着跨应用程序域边界的方法会被同步地执行。在任何给定的时刻,一个线程都被认为只存在一个应用程序域中,我们可以调用System.Treading的静态GetDomain方法来获得当前执行线程所在的应用程序域。
许多Asp.NET和Windows进程都含有多个AppDomain。Asp.net使用这种技术来隔离WEB应用程序,使得我们不必在为每一个服务器上的虚拟root来启动一个新的Windows进程。

AppDomain并不会改变进程,线程其间的关系,每个进程有一个主线程,也可能含有其他的线程,即使在Asp.net进程中,拥有多个AppDomain也只有一个主线程,Asp.net会创建其他的线程,所有多个WEB应用程序可同时执行,但在整个进程中就仅有一个主线程。
*****
******
线程调度:
时间片和时间共享技术。在单CPU上任何时刻最多只有一个线程在运行(不考虑超线程处理器),为了提供一个“同时”执行多个任务的假象,OS从来不会让一个线程长期的运行,他会为每个线程分配一小段的时间,每个线程被允许执行的时间被称为“quantum”(那个单词好像很有历史意义,暂且认为是时间片的同义词),尽管每个“quantum”非常小,典型的是20毫秒。在一个线程运行了一个时间片之后,OS停止它并让其他的线程运行,当它的时间片到期后又会让其他的线程继续运行,如此下去.....。一个线程可以也在其时间片到期之前主动放弃的的CPU占用权
因为线程运行的时间片长度很短,所以我们几乎感觉不到线程是被切换着运行,如同卡通片的原理,大约以每秒23帧的频率更换图片,我们就感觉不到闪烁。
在Windows中执行的实体是线程,OS主要集中于线程的调度并保持CPU总是处于繁忙状态,OS从来不会调度进程或是应用程序域。进程和应用程序域只不过是维护你代码的内存区域,线程才是被执行的代码。
线程具有优先级,windows总是允许高优先级线程运行在底优先级的线程前面,实际上如果一个更高的优先级线程将要运行,Windows会“切短”低优先级线程的时间片长度,从而允许高优先级线程尽快运行,总之Windows更偏向于高优先级线程(不是平等的世界)。
线程可能自愿在其时间片耗完之前挂起自己,这种现象经常发生,比如一个线程想读取一个文件中的数据,但IO子系统会占用大量的时间来定位文件之后再提取数据,这时你不能让CPU处于空闲Idle状态,而便于让其他线程运行,而是你的线程进入等待状态来指出它在等待外部事件。Windows调度器立即定位并运行下一个线程,保持CPU繁忙,此时挂起的线程会等待它的数据准备完毕。

停止一个线程并运行另一个线程的动作称为上下文切换。它进行的非常快,发生于每个活动线程的每一个Quantum(暂解为时间片)的结尾期。因为上下文切换的存在,引入大量的线程到你的程序中不是一个明智的做法,不要让切换的代价高过你执行任务的代价,你需要均衡你应用程序所需的线程数量以及操作系统可处理的线程数量,没有经验数据告诉你应该创建多少个线程是合适的,唯一记住的是上下文切换的存在且多实践吧!。
******
*******
大部分的.net框架基础类库都不是线程安全的,线程安全的代码是那些可同时被多个线程调用并且不产生边沿效应。如果线程不是线程安全的,同时从多个线程调用代码
可能导致不可测的结果,更甚者导致程序崩溃。当处理非线程安全的对象时,保证多个线程不会同时访问该对象的方法。查找一个.net基础类库中的某个方法是否线程安全的,请参阅在线帮助,如果没提到方法是线程安全的,那么该方法就非线程安全的。
.net框架的WindowsForms子集 不仅是非线程安全的,它还有线程亲和力,线程亲和力是指,由一个线程创建的对象只能由那个线程来使用。其他的线程甭想指染它。在WinForm环境下,必须保证多线程(后台)从来不会直接与WindowsForms对象交互(如forms,controls)这很重要,当在创建交互式,多线程应用程序中,必须确保只有创建一个Form的那个线程才可以与那个Form交互。
*******
使用时机:
应用软件主要使用线程,来为用户提供一个最佳体验。
大部分情形是,做一些“后台工作”,我们开发者主要使用线程来改善用户体验。
服务性软件,使用多线程来提供可伸缩性和服务质量(比如并行处理请求)。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值