线程与进程Word下载.docx

上传人:b****1 文档编号:5837769 上传时间:2023-05-05 格式:DOCX 页数:44 大小:113.03KB
下载 相关 举报
线程与进程Word下载.docx_第1页
第1页 / 共44页
线程与进程Word下载.docx_第2页
第2页 / 共44页
线程与进程Word下载.docx_第3页
第3页 / 共44页
线程与进程Word下载.docx_第4页
第4页 / 共44页
线程与进程Word下载.docx_第5页
第5页 / 共44页
线程与进程Word下载.docx_第6页
第6页 / 共44页
线程与进程Word下载.docx_第7页
第7页 / 共44页
线程与进程Word下载.docx_第8页
第8页 / 共44页
线程与进程Word下载.docx_第9页
第9页 / 共44页
线程与进程Word下载.docx_第10页
第10页 / 共44页
线程与进程Word下载.docx_第11页
第11页 / 共44页
线程与进程Word下载.docx_第12页
第12页 / 共44页
线程与进程Word下载.docx_第13页
第13页 / 共44页
线程与进程Word下载.docx_第14页
第14页 / 共44页
线程与进程Word下载.docx_第15页
第15页 / 共44页
线程与进程Word下载.docx_第16页
第16页 / 共44页
线程与进程Word下载.docx_第17页
第17页 / 共44页
线程与进程Word下载.docx_第18页
第18页 / 共44页
线程与进程Word下载.docx_第19页
第19页 / 共44页
线程与进程Word下载.docx_第20页
第20页 / 共44页
亲,该文档总共44页,到这儿已超出免费预览范围,如果喜欢就下载吧!
下载资源
资源描述

线程与进程Word下载.docx

《线程与进程Word下载.docx》由会员分享,可在线阅读,更多相关《线程与进程Word下载.docx(44页珍藏版)》请在冰点文库上搜索。

线程与进程Word下载.docx

明白进程是系统进行资源分配和调度的单位非常重要,内存和CPU都是系统资源,当一个程序被调入内存开始执行时就变成了进程,此时操作系统便为其分配了这些相关的资源并且负责进行调度。

进程是将,这个将直接对操作系统这个国王负责,国王可以分配给他一定的土地和俸禄(对应系统资源)并指派他去完成特定的任务。

一个国家日理万机的大将可以有很多,这也就是操作系统多进程的概念,操作系统这个国王负责调兵遣将。

按照定义,线程是操作系统分配处理器(CPU)时间的基本单元,是系统中最小的执行单元。

如前所述,进程如将,线程如兵,操作系统创建并控制进程,进程包含和控制线程。

我们知道国王和将帅自己并不去攻城掠地,他们只是坐阵指挥。

那么实际上真正进行攻城掠地的是兵(线程)。

兵也有自己的资源(系统会为线程初始化一个线程内核对象,还有一块1M左右的内存堆栈)。

作为将要善于谋略,善于部署,善于将兵,拥兵十万不如精甲十千。

作为兵要众志成城、竭尽全力去完成自己的任务。

所以线程不可滥用,进程应当精简(一个进程只需做一个任务就够了)。

多进程决定了操作系统的多任务。

但是我们知道我们往往只有一个CPU,一个CPU在同一时间只能做一件事情,多任务又是怎么实现的呢?

我们知道要真正完成某个任务的是线程,对于进程来讲至少会带有一个默认的线程,我们称之为主线程。

我们先假设进程都带有一个线程。

线程要执行就需要CPU,我们知道现今CPU因为执行速度非常快,它没有必要单独为一个线程服务,因此它将自己一秒的时间进行切片,每片有1毫秒左右(这个微软没有具体说明,是由操作系统内部参数来控制这个时间值,具体来说跟CPU速度有关,速度越快时间片切的越小),然后它就以时间片为单位向外提供服务。

比如在一秒钟内A线程占有10个时间片,B线程占有30个时间片……每一秒都这样分配了以后,操作系统负责CPU的切换,于是一秒钟过后所有线程都执行了,整体看上去好像所有的进程是在同时运行,这就是操作系统多任务的实现方式,是通过不断切换线程执行实现的。

下面是一个CPU利用图(图13.2),操作系统负责进行线程之间的切换:

图13.2 

线程原理图

从上图首先可以看出,对于单个线程来讲抢占的CPU时间越多它完成的事情就越多,也可以说是执行就越快。

要让某个线程抢占CPU的能力增加,你可以提高该线程的优先级,通常来说优先级越高的线程抢占CUP能力越强,当然,大部分情况下不需要这么做。

因为线程是抢占CPU的主力军,所以我们可以用增加线程数目的方式提高进程的执行速度。

从一般意义上讲,进程在完成任务时用的线程越多任务就完成的越快,正所谓三军之众,可使必受敌而无败。

我们从CPU时间片的角度举一个通俗的例子,假如给你一星期时间,你将它切片,每天为一片。

假如你有三个女朋友,你和这三个女友的感情进展就可以看作是三条线程,那么如果她们其中一个获得4个时间片去发展感情,另外两个都是1个时间片,如此常此以往,很显然与拥有四个时间片的女友感情进展最快。

使用线程

在C#中线程的相关内容是通过System.Threading命名空间实现的。

这个命名空间里提供了多个类、接口、枚举来支持多线程的实现。

你可以在这个命名空间中找到最重要的类——就是线程类Thread。

我们可以通过它创建并控制线程,设置线程优先级并获取其运行状态等。

现在就让我们进入线程世界吧!

认识Thread类并创建你的第一个带线程的程序

首先我们需要看看Thread类的属性和方法,Thread类的重要属性和方法如下表13.1:

表13.1

属性

说明

CurrentThread

静态属性,获取当前正在运行的线程

IsAlive

获取一个值,该值指示当前线程的执行状态

IsBackground

获取或设置一个值,该值指示是否是后台线程

Name

获取或设置线程的名称

Priority

获取或设置一个值,该值指示线程的调度优先级

ThreadState

获取一个值,该值包含当前线程的状态

方法

Start

开始执行线程

Abort

终止线程

Interrupt

打断处于WaitSleepJoin线程状态的线程,使其继续执行

Join

阻止调用线程,直到被调用线程终止为止,它在被调用线程实际停

止执行之前或可选超时间隔结束之前不会返回

Sleep

静态方法,使当前线程停止指定的毫秒数

要创建一个线程的实例并不复杂,我们知道线程必定跟一个执行方法相关联,这样线程启动后才 

会有事情给它做。

应用程序的主线程总是从Main方法开始,而后其他的线程需要在程序里自己定义 

和启动。

我们又知道委托可以代表一个方法,所以创建线程实例时只需要在Thread类的构造方法里传 

入一个委托实例即可,这个委托已经在线程命名空间中定义好了,叫ThreadStart,所以创建线程方式 

如下:

Thread线程对象实例=newThread(newThreadStart(方法名));

这里要注意的是,在委托ThreadStart的构造方法里面传入的是方法名,这个方法可以是静态方法,也可以是某个对象的方法。

线程对象创建后,我们就可以调用其Start方法开始线程的执行了。

我们可以在主线程里建立线程,也可以在线程里再创建线程,线程启动后会自动执行委托实例代表的方法,线程执行完后会自动销毁并释放其资源。

下面我们就来建立一个线程,代码如下:

usingSystem;

usingSystem.Threading;

classProgram

{

staticvoidMain(string[]args)

//设置主线程名字

Thread.CurrentThread.Name="

主线程"

;

Console.WriteLine("

主线程启动"

);

//在主线程里创建子线程

Threadth=newThread(newThreadStart(ThreadProc));

//启动子线程

th.Start();

//主线程开始数数

for(inti=0;

i<

10;

i++)

{0}:

{1}"

Thread.CurrentThread.Name,i);

Thread.Sleep

(1);

//让当前线程休眠毫秒

}

//线程启动后执行的方法,这里是用了静态方法

staticvoidThreadProc()

//当前线程是子线程,此时是设置子线程名字

子线程"

子线程启动"

//子线程开始数数

运行结果(图13.3):

图13.3 

运行结果

上面这个例子,我们在主线程里建立了一个子线程,并让其执行方法ThreadProc。

从运行结果可以看出主线程和子线程的运行基本是同步的。

主线程建立完子线程后便立即去执行数数操作,子线程开始后也立即去数数,两个线程各数各的并保持同步。

事实上这俩兄弟并没有那么和谐,如果你把上面的Thread.Sleep语句都去掉后,它们就不同步了,原因何在?

我们前面提到过,线程是靠争抢CPU而执行的,如果去掉Thread.Sleep,语句就会出现争抢CPU的现象,如果是这样那么鹿死谁手还是不一定的事情。

如果加上了Thread.Sleep,当主线程数完一个数后就休眠了,此时CPU是空闲的(如果不考虑其他系统正在运行的进程),那么子线程就可以在此时获得CPU并数数,等到子线程数完一个数后,它也休眠……如此一来一去,兄弟双双把数数的局面就出现了。

这里要特别注意一下Thread类中静态属性CurrentThread和静态方法Sleep的使用,这些静态属性和静态方法是针对当前线程的操作。

我们知道,当进程一启动就会带有一个主线程,这个线程不是我们自己定义的,我们想要操作它的实例只能通过静态属性或静态方法。

比如上面例子中,开始时我们通过Thread.CurrentThread的Name属性来设置主线程的名字。

当然,这些静态属性或方法也可以放在子线程里,所以对于子线程的实例至少可以通过两种方式来获得,一种是通过定义时的线程对象(如上面Threadth中的th)来获得,一种就是通过线程类的静态属性Thread.CurrentThread来获得。

线程的IsBackground属性是用于将线程设置为后台线程。

.NET中共有两种类型的线程,一种是前台线程,一种是后台线程。

它们的区别在于,后台线程会随着主线程的结束而结束,而前台线程,应用程序要等待前台线程结束应用程序才能结束。

当给IsBackground属性赋值true时就指明了你建立的是后台线程,如果你建立线程时不指明类型,那么默认是前台线程。

属性中的Priority用来设定线程的优先级。

我们说线程是有优先级的,优先级决定线程争抢CPU的能力,因此优先级高的线程执行速度和效率会快一些。

关于线程的优先级在后面会详细介绍,这里不再多说。

线程的ThreadState属性是用来得到线程运行状态的,这个属性在后面也会有详细介绍。

对于IsAlive属性,它是用来判断线程是否正在运行的,比如我们可以判断当前线程是否终止,如果没有终止那么我们可以终止掉它:

if(th.IsAlive)th.Abort();

对于线程执行的方法只要满足委托ThreadStart的类型即可,所以我们需要看一下系统委托ThreadStart的原型。

ThreadStart的原型定义如下:

publicdelegatevoidThreadStart();

不难看出,线程执行的方法需要没有参数,并且也无返回值。

这个方法可以是某个对象的实例方法,也可以是某个静态方法。

也就是说线程的方法可以是满足ThreadStart的任何方法,甚至它可以和主线程共用一个方法,我们来看下面代码:

Thread.CurrentThread.Name="

Threadth=newThread(newThreadStart(DoWork));

th.Name="

DoWork();

staticvoidDoWork()

这段代码跟刚才那个示例的执行结果一模一样,为什么会这样呢?

事实上跟上面我们提到的原理一样,CPU在某个时间点上只能执行一个方法。

DoWork此时就好像一个数数的工具,先是主线程拿它来数一下自己的数,然后空闲的时候子线程再拿它来数一下自己的数,两个线程虽然用了同一个方法,但还是各自操作各自的,跟使用两个方法没有区别。

线程的方法和状态

线程的方法中,Start方法我们已经使用过了,至于Abort是停止线程的方法,Interrupt是让线程从暂停或睡眠中苏醒并继续执行的方法。

从线程的生命周期来看,调用线程的Start方法后线程进入激活状态,此后线程进行操作,如果中间调用了Sleep方法那么线程将出现暂停状态;

此时如果线程调用了别的线程的Join方法那么本线程会被暂停进入等待状态;

当然最后我们可以对线程调用Abort方法使线程终止并销毁。

每一种线程的方法都会对自己或者别的线程运行状态造成影响。

我们可以通过线程的属性ThreadState来获得线程的运行状态。

线程命名空间为我们提供了一个叫ThreadState的系统枚举(注意跟线程的ThreadState属性重名),它包含线程各种状态的定义。

ThreadState枚举的成员:

Aborted,线程处于Stopped状态中。

AbortRequested,已对线程调用了Thread.Abort方法后的挂起状态。

Running,线程已启动,正在运行中。

Stopped,线程已停止。

Unstarted,尚未对线程调用Thread.Start方法。

WaitSleepJoin,由于调用Sleep或Join,线程已暂停。

假设有两条线程A和B,我们来看看线程方法和状态之间的关系,这里要特别注意方法的调用者。

因为有的方法是别的线程调用的,而有的方法需要自己本线程调用。

下面是操作和状态关系的对照表(表13.2)(来自微软公司MSDN),这个表并不是按线程产生到消亡的顺序进行的,主要是展示线程之间的方法调用和运行状态之间的关系:

表13.2

线程A

线程B

线程A状态

线程B状态

A线程被创建但未调用Start方法

Unstarted

对A调用A.Start()

Running

调用Thread.Sleep()

WaitSleepJoin

对B调用B.Join()

Running

对A调用A.Interrupt()

由WaitSleepJoin变为Running

A.Abort

Stopped

从上面的表中我们可以看出线程从生成对象到最后中止一般会出现四个状态,按照先后顺序依次是Unstarted、Running、WaitSleepJoin和Stopped,其中WaitSleepJoin状态可以出现也可以不出现。

关于线程的方法,可能Join最难理解,当前线程调用别的线程Join时,当前线程就会进入等待状态,等待调用线程完成所有操作后,当前线程才能继续执行(假设在A线程中调用了B.Join()那么就好像A对B说“B同志你赶快做,等你做完了我再继续”)。

Join方面有两个版本,一个是不带参数的,调用形式如A.Join();

一种是带有时间参数的,调用形式如A.Join(20),此时Join的方法里面时间表示当前线程最多能等待调用线程的毫秒数,如果超过这个时间那么当前线程就不等了继续往下执行。

我们来看一个例子:

classTest

//时间变量,初始化为1000毫秒

staticintwaitTime=1000;

publicstaticvoidMain()

主线程开始"

//创建线程并开始

ThreadnewThread=newThread(newThreadStart(Work));

newThread.Start();

//调用Join方法,等待2秒钟

if(newThread.Join(2*waitTime))

新的线程结束"

else

Join操作超时"

主线程结束"

staticvoidWork()

新的线程被执行"

Thread.Sleep(waitTime);

运行结果:

主线程开始

新的线程被执行

新的线程结束

主线程结束

在这个例子中我们在主线程里创建一条线程newThread,创建完后随即启动该线程。

然后在主线程里调用了Join方法,调用后主线程处于等待状态,等到子线程newThread执行完成后,主线程才继续进行。

我们在Join方法里设置了等待时间值,如果超过这个时间那么主线程就不等了继续往下执行(这也是为什么把等待时间设为子线程停留时间的两倍的原因);

如果你把子线程方法里面的Thread.Sleep方法停留时间加长那么就会出现“Join操作超时”的运行结果。

如果Join没有参数,那么主线程就会一直等到子线程结束才能继续往下执行。

线程的优先级及实用实例

我们说线程靠抢CPU时间片而执行,谁抢的多谁利用CPU的时间就多也就执行得快。

而决定这个争抢能力的就是线程的优先级,线程优先级高的在同一时间越能获得CPU时间片。

你可以为线程指定由ThreadPriority枚举定义的优先级,默认情况下创建线程的优先级是ThreadPriority.Normal,原则上相同优先级的线程会获得相同的CPU时间。

一旦给线程设置了优先级,那么操作系统会根据线程的优先级调度线程的执行。

这里要注意一个问题,操作系统可以在线程间切换时动态地调整线程的优先级,这样的话也就是说有时候你设的优先级可能得不到给定的效果,因为此线程可能已经被操作系统更改了优先级。

另外,线程的优先级不影响该线程的运行状态,你只要确保该线程的状态在操作系统调度该线程之前为Running就可以了,你可以在线程定义时或线程运行时随时改变线程的优先级。

线程的调度优先级:

AboveNormal,处于Normal优先级之上但低于Highest优先级。

BelowNormal,处于Normal优先级之下但高于Lowest优先级。

Highest,最高的优先级。

Lowest,低于BelowNormal的最低优先级。

Normal,默认情况下线程具有Normal优先级。

下面的代码示例说明了更改线程优先级的效果。

我们创建了两个线程,其中一个线程的优先级设置为BelowNormal,一个线程的优先级使用其默认的Normal。

两个线程都使用同一个方法进行数数,两个线程运行一段设定的时间。

示例代码如下:

staticvoidMain()

PriorityTestwork=newPriorityTest();

//创建线程并设置线程执行方法

ThreadthreadOne=newThread(newThreadStart(work.ThreadMethod));

threadOne.Name="

线程1"

ThreadthreadTwo=newThread(newThreadStart(work.ThreadMethod));

threadTwo.Name="

线程2"

//设置优先级

threadTwo.Priority=ThreadPriority.BelowNormal;

threadOne.Start();

threadTwo.Start();

//让两个线程都计算2秒钟

Thread.Sleep(2000);

//停止计算

Work.LoopSwitch=false;

classPriorityTest

//用来控制While循环,为false就退出While循环

boolloopSwitch;

//构造方法

publicPriorityTest()

loopSwitch=true;

publicboolLoopSwitch

set{loopSwitch=value;

}

//线程的方法,执行数数操作

publicvoidThreadMethod()

longthreadCount=0;

//进行加法操作

while(loopSwitch){threadCount++;

//显示结果

{0},优先级:

+"

数到:

{2}"

Thread.CurrentThread.Name,

Thread.CurrentThread.Priority.ToString(),

threadCount.ToString());

线程1,优先级:

Normal数到:

917142792

线程2,优先级:

BelowNormal数到:

42614664

很显然线程优先级高的线程1数的数要多一些,也就是说它执行的快一些。

这里还要注意一个问题,线程的优先级还跟平台有关。

不同的操作系统会对线程的调度不同,也就是说你在Windows下设的优先级到其他操作系统下可能一点用都没有。

当然,关于线程的优先级说了这么多也是白说,实际上老鸟们建议不要随便提高线程的优先级,如果线程优先级过高可能会影响其他线程的执行,从而导致严重的、难以预料的、不堪设想的后果。

线程的同步

在介绍线程同步这个概念之前我们先来看一个简

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 人文社科 > 法律资料

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2