您好,欢迎访问三七文档
当前位置:首页 > 商业/管理/HR > 信息化管理 > 第14章-多线程浙江农林.
•线程(Thread)是程序中一个控制的执行流程,属进程的一个实体。•多任务操作系统就是采用多进程和多线程机制,即在同一时间内有多个进程在运行,一个进程可以有若干个线程即为多线程。•采用多线程技术的目的是提高程序运行速度和CPU资源利用率。•本章主要讨论MFC的多线程程序设计方法。多线程基础14.1多线程编程14.2线程的终止14.3线程的优先级与管理14.4线程之间的通信14.5线程的同步14.614.1多线程基础•多线程技术是多任务并发程序设计的基础,是提高程序运行速度和增强数据处理能力的重要技术手段。•实际中,常常采用多线程编程技术提高应用程序的性能。14.1.1进程与线程•进程(Process)是程序在计算机内存中的运行活动,是系统资源分配和调度的基本单位,是程序(Program)即指令集合和相关数据的动态体现。•进程和程序的区别如下:•(1)进程描述的是程序的动态行为,而程序是一个指令序列和相关数据的静态描述;•(2)进程是程序的一次运行活动,具有暂时性,而程序可以脱离机器长期保存,具有永久性;•(3)一个程序可以对应多个进程,一个进程也可以有多个程序,二者没有确定的对应关系;•进程是为了刻画程序内部运行状态而引入的一个概念。•线程是由进程创建的可执行单元,线程依附于进程的存在而共享进程的内存空间,由应用程序提供多个线程执行控制。•线程也可以创建线程。线程和进程一样具有一个生存周期,在这个生存周期中,总是处于某种状态之中,诸如就绪态、运行态或等待(阻塞)态。•当进程退出运行以后,线程也随之消失,所占用的资源也一同释放。•所以,在下列情况可以采用多线程编程技术:•(1)为了提高运行效率,在同一时间内运行多个任务时;•(2)处理数据量比较大,需要等待时;•(3)同一程序内没有顺序关系的代码段时;•(4)应用系统采用客户/服务器机制时。•程序设计使用多线程还要注意以下几点:•(1)多线程实际是多个程序段同时存在并运行于内存中,不要让太多的线程使系统逻辑结构变得复杂,线程并不是越多越好;•(2)有些情况下需要处理线程的同步问题;•(3)搞清楚线程的优先级设置和调度规则;•(4)搞清楚线程间的数据交换和通讯问题。14.1.2线程分类•MFC将Windows的线程处理功能封装成一个CWinThread线程类,使程序设计更加方便简捷。•MFC将Windows线程分为两类:一类是用于人机交互、处理用户输入的线程,称为用户界面线程(User-InterfaceThreads);另一类是完成不需要用户干预的或后台执行的操作,称为工作者线程或辅助线程(WorkerThreads)。••但对于WindowsAPI来说,由于它没有引入类的概念,所以没有用户界面线程和工作者线程之分,将二者等同处理,统称为线程。14.2多线程编程•程序设计中采用多线程编程技术,可以有两种途径实现。•一是采用WindowsAPI提供的进程创建函数CreateThread()进行创建,用挂起、恢复和终止、优先级控制等函数实现线程管理;二是采用MFC提供的AfxBeginThread()函数创建,由CWinThread类进行管理。•CWinThread封装了Win32API有关线程操作的函数。•本节在讲述Win32API线程处理函数的基础上,主要讨论用MFC提供的线程函数创建工作者线程和用户界面线程的方法。•用户界面线程和工作者线程的主要区别是:前者需要响应用户输入和处理系统产生的事件与消息,拥有自己的消息队列和消息循环;而后者不需要处理这些消息和事件,没有消息队列和消息循环。14.2.1Win32API线程处理•WindowsAPI提供的线程操作函数有创建、挂起、恢复、终止以及优先级控制等。下面简单介绍这几个函数。1.线程创建•函数原型如下:•HANDLECreateThread(•LPSECURITY_ATTRIBUTESlpThreadAttributes,•DWORDdwStackSize,•LPTHREAD_START_ROUTINElpStartAddress,•LPVOIDlpParameter,•DWORDdwCreationFlags,•LPDWORDlpThreadId•);2.线程挂起•函数原型如下:•DWORDSuspendThread(HANDLEhThread)3.线程恢复•函数原型如下:•DWORDResumeThread(HANDLEhThread);14.2.2工作者线程•工作者线程是由MFC提供的函数创建的,它用于后台处理一些费时操作,如大数据量计算、文件读写等操作,它没有消息循环。工作者线程的创建比较简单,直接调用MFC的AfxBeginThread()函数就可以。•该函数原型如下:•CWinThread*AfxBeginThread(AFX_THREADPROCpfnThreadProc,•LPVOIDpParam,•intnPriority=THREAD_PRIORITY_NORMAL,•UINTnStackSize=0,•DWORDdwCreateFlags=0,•LPSECURITY_ATTRIBUTESlpSecurityAttrs=NULL);•【例14-1】创建一个工作者线程。步骤如下:图14.1工作者线程设计阶段外观图14.2工作者线程运行时界面14.2.3用户界面线程•用户界面线程就是响应界面操作的线程,就像MFC中创建的对话框一样。•当应用程序需要处理用户输入并响应系统产生的事件和消息时,可以通过创建用户界面线程实现。•在MFC中创建用户界面线程比创建工作者线程稍麻烦些,仍然需要调用MFC的AfxBeginThread()函数的另一个版本。•使用这个函数创建用户界面线程时,函数的入口参数与工作者线程有所区别。•该函数原型如下:•CWinThread*AfxBeginThread(CRuntimeClass*pThreadClass,•intnPriority=THREAD_PRIORITY_NORMAL,•UINTnStackSize=0,•DWORDdwCreateFlags=0,•LPSECURITY_ATTRIBUTESlpSecurityAttrs=NULL);•【例14-2】创建一个自己的用户界面线程,具体步骤如下:图14.3用户界面线程主窗口设计阶段外观图14.4用户界面线程外观图14.5从CWinThread派生用户界面线程窗口外观图14.6用户界面线程演示主窗口图14.7用户界面线程窗口14.3线程的终止•一般情况下,线程执行完成后就自动结束即正常终止。•如果线程没有执行完预定任务或需要由外部某种事件强制结束称为异常终止。•线程除正常执行完毕外,在调用了ExitThread()函数、ExitProcess()函数、TerminateThread()函数和TerminateProcess()函数后都可以终止线程的运行。•由MFC创建的进程也可以由这些函数终止运行。14.3.1线程的正常终止•通常,线程执行到线程函数的结尾时,系统会自动调用Win32API函数ExitThread()终止该线程,用户不需要干预就可以结束一个线程,但如果某些条件需要线程退出运行,就需要编程调用函数ExitThread()。•该函数原型如下:•VOIDExitThread(DWORDdwExitCode)14.3.2线程的异常终止•当线程没有运行结束时强行终止线程的执行称为异常终止,异常终止需要调用Win32API函数TerminateThread()终止线程的运行。•该函数原型如下:•BOOLTerminateThread(HANDLEhThread,CDWORDdwExitCode)14.4线程的优先级与管理•在多任务操作系统,如Windows、UNIX中,将进程和线程按其性质分为不同类型,然后根据各自的类型,分别赋予不同的优先级,方便系统的调度和控制。14.4.1线程的优先级•如前所述,同一进程中的各个线程共同分享进程的CPU资源。•CPU时间的分配是由系统进程(线程)调度程序控制的。•调度的一个基本原则是根据进程的优先级进行时间片分配。•线程也有自己的优先级,线程的优先级取决与两个方面的因素:线程所在进程的优先级和线程本身的优先级。•也就是说,线程的实际优先级是由上述两个优先级组合成的优先级,即基本优先级确定的。•其中,进程的优先级分为4个等级:•(1)IDLE_PRIORITY_CLASS•(2)NORMAL_PRIORITY_CLASS•(3)HIGH_PRIORITY_CLASS•(4)REALTIME_PRIORITY_CLASS•这4个等级的优先级顺序依次增加,即REALTIME_PRIORITY_CLASS的优先级最高。•线程的优先级则是以进程的优先级为基础,通过进程的优先级和线程的优先级计算出线程的基本优先级。•线程的优先级分为7个等级:•(1)THREAD_PRIORITY_IDLE•(2)THREAD_PRIORITY_LOWEST•(3)THREAD_PRIORITY_BELOW_NORMAL•(4)THREAD_PRIORITY_NORMAL•(5)THREAD_PRIORITY_ABOVE_NORMAL•(6)THREAD_PRIORITY_HIGHEST•(7)THREAD_PRIORITY_TIME_CRITICAL•这7个等级的优先级依次提高,THREAD_PRIORITY_TIME_CRITICAL的优先级最高。14.4.2线程的优先级管理•从14.2节创建线程的过程可以看出,无论创建的是工作者线程还是用户界面线程,每个线程在创建时都有一个优先级(实例采用默认优先级THREAD_PRIORITY_NORMAL)。••线程创建后的优先级可以根据实际情况改变。•MFC中CWinThread类提供的方法就可以设置和访问线程的优先级。1.获取线程的优先级•CWinThread类获取线程优先级的函数原型如下:•BOOLSetThreadPriority(intnPriority)2.设置线程的优先级•CWinThread类设置线程优先级的函数原型如下:•intGetThreadPriority(void)14.4.3线程的调度•我们知道,线程在一个生存周期中,总是处于就绪、运行或阻塞状态的某一个状态之中。•系统线程调度程序总是从线程就绪队列中调度某个线程投入运行。•如果就绪队列中有多个线程的级别相同,系统就会为这些线程中的每个线程平均分配CPU的时间;若这些线程中有级别高的线程,系统就会分配CPU时间片让高级别的线程投入运行,只有级别高的线程运行完以后,低级别的线程才能获得CPU的时间片投入运行。•每一个线程运行时要占用一个CPU,因此,单CPU的计算机系统只能有一个线程。•线程的优先级在0~15的称为普通优先级,是应用程序中线程经常使用的优先级。•线程的优先级在15~31的统称为实时优先级,它与普通优先级的最大区别是相同优先级的线程运行不轮流占用CPU时间片,而是先运行的线程先控制CPU,如果它不主动放弃对CPU的控制,同级或低级的线程就无法得到运行。•为了使低级别的线程也能够执行,只能将高级别线程挂起。•这是因为Windows是一个强占式多任务的操作系统,即任何时候系统都可以中断一个线程,强迫这个线程放弃CPU的使用权,并把CPU的使用权交给另一个线程。•在VisualC++6.0开发工具包中,提供了一个用于观察系统中运行的进程和线程情况的实用工具ProcessViewer。图14.8使用ProcessViewer浏览Exam14-2实例的线程14.5线程之间的通信•我们知道,应用程序中创建的工作线程总是为主线程执行某种特定的任务。•这样,主线程和工作线程之间必须建立一种信息传递机制,也就是线程间的通信。•线程间的通信方式主要有全局变量方式和用户自定义消息方式。•下面讨论这两种方式是如何实现线程间通信的。14.5.1通信机制•采用全局变量的方式进行线程间通信的机制非常简
本文标题:第14章-多线程浙江农林.
链接地址:https://www.777doc.com/doc-2120016 .html