第2章单机资源共享的应用编程

整理文档很辛苦,赏杯茶钱您下走!

免费阅读已结束,点击下载阅读编辑剩下 ...

阅读已结束,您可以下载文档离线阅读编辑

资源描述

Windows网络编程技术第2章单机资源共享的应用编程授课老师:胡鸣数学与计算机学院计算机系教学目的•理解进程,线程和动态连接库的概念;•掌握进程的创建方法,进程间的通信;•掌握线程创建的方法,多线程间的通信;•掌握多线程的同步机制;•掌握动态链接库的编写和使用;本章提纲•2.1进程间通信–2.1.1进程间通信应用实例及概念–2.1.2进程的创建与终止–2.1.3内存文件映射•2.2多线程通信–2.2.1多线程应用实例及概念–2.2.2线程的创建、挂起、激活和终止–2.2.3线程的优先级•2.3同步控制机制–2.3.1同步控制应用实例及意义–2.3.2同步控制类型及应用条件–2.3.3应用实例的算法与实现•2.4动态链接库–2.4.1静态链接库与动态链接库的应用实例–2.4.2动态链接库的创建和调用方法–2.4.3动态链接库应用的条件2.1.1进程间通信应用实例及概念•程序和进程应用程序和进程在概念上是有一定区别的,前者是静态的程序代码,而后者是动态的实体。只有应用程序加载到系统中后才能成为一个进程。•独立进程和共享进程独立运行的程序称为独立进程;另外,应用程序可能启动多个进程,一个进程空间可以运行多个程序,这就是共享进程。•我们以第二章代码“命名管道”为例来了解进程间通信的基本情况。进程A通过命名管道(后面会介绍)的方式传递两个参数给进程B,进程B将这两个参数进行计算后,把结果通过命名管道的方式返回给进程A。•具体的过程结合下面的图来描述:进程间通信实例创建命名管道NamedPipeNamedPipe打开命名管道NamedPipe进程B进程A向管道中写入数据连接管道读取管道中的数据处理完毕后写入读取管道中的数据关闭管道创建进程B•进程A先启动,然后创建进程B,;•进程B创建成功后先创建命名管道,然后创建并连接一个命名通道。•进程A打开进程B建立的命名管道,同时向命名管道写数据,进程B获取到进程A传过来的数据,进行处理并将结果传回给进程A2.1.2进程的创建与终止•在上面的例子中,进程A有一个操作是创建进程B。创建进程的函数是:CreateProcessBOOLCreateProcess(LPCTSTRlpApplicationName,//执行程序文件名LPTSTRlpCommandLine,//参数行LPSECURITY_ATTRIBUTESlpProcessAttributes,//进程安全参数LPSECURITY_ATTRIBUTESlpThreadAttributes,//线程安全参数BOOLbInheritHandles,//继承标记DWORDdwCreationFlags,//创建标记LPVOIDlpEnvironment,//环境变量LPCTSTRlpCurrentDirectory,//运行该子进程的初始目录LPSTARTUPINFOlpStartupInfo,//创建该子进程的相关参数LPPROCESS_INFORMATIONlpProcessInformation//创建后用于被创建子进程的信息•);进程创建与正常结束•进程是应用程序的执行实例,进程创建成功后,操作系统会给该进程分配私有的虚拟地址空间、代码、数据和其他系统资源;进程结束后,操作系统会回收该进程所占用的系统资源。一般来讲(不使用特殊技术)进程是无法突破进程边界存取其他进程内的存储空间里的数据,这也是我们要学习进程通信的原因。•当主线程的进入点函数返回时,进程也就随之结束。这种进程的终止方式是进程的正常退出,进程中的所有线程资源都能够得到正确的清除。除了这种进程的正常退出方式外,有时还需要在程序中通过代码来强制结束本进程或其他进程的运行。进程强制结束•1.使用ExitProcess()结束进程ExitProcess()函数的原型为:voidExitProcess(UINTuExitCode);•2.使用TerminateProcess()结束进程ExitProcess()只能强制执行本进程的退出,如果要在一个进程中强制结束其他进程就要用TerminateProcess()来实现。BOOLTerminateProcess(HANDLEhProcess,UINTuExitCode);•应该尽可能的让进程正常退出;•在强制终止进程的时候应该考虑资源释放的问题;2.1.3内存文件映射•前面讲到过,每个进程有自己的地址空间,一个进程不能轻易地访问另一个进程地址空间中的数据,必须采用特殊的方式来进行进程间的通信。本节以第二章代码“内存文件映射”为例介绍利用内存文件映射实现进程间通信。•1、利用内存映射文件进行文件I/O操作,进行文件I/O操作需要下面几个步骤:步骤一:调用CreateFile()函数,以适当的方式创建或打开一个文件核心对象;如果是内存文件,这一步忽略;步骤二:把CreateFile()函数返回的文件句柄作为参数,传给CreateFileMapping()函数,由CreateFileMapping()函数创建一个文件映射核心对象的适当属性;如果是内存文件,则句柄是:0xFFFFFFFF;步骤三:创建了文件映射核心对象后,调用MapViewOfFile()函数,告诉系统把文件的哪一部分映射到进程的地址空间中,以何种方式映射;步骤四:利用MapViewOfFile()函数返回的指针来使用文件数据;•步骤五:操作完毕后,调用UnmapViewOfFile()函数,告诉系统撤销对文件映射核心对象的映射;•步骤六:使用CloseHandle()函数关闭文件映射核心对象;•步骤七:使用CloseHandle()函数关闭文件核心对象;2.2.1多线程应用实例及概念•多线程是这样一种机制,它允许在程序中并发执行多个指令流,每个指令流都称为一个线程,彼此间互相独立。线程又称为轻量级进程,它和进程一样拥有独立的执行控制,由操作系统负责调度,区别在于线程没有独立的存储空间,而是和所属进程中的其它线程共享一个存储空间,这使得线程间的通信远较进程简单。•多线程和传统的单线程在程序设计上最大的区别在于,由于各个线程的控制流彼此独立,使得各个线程之间的代码是乱序执行的,由此带来的线程调度,同步等问题。•存钱和取钱的例子,我们利用第二章代码“三线程同步”来说明。例子造成这种结果的原因是由于各个线程的控制流彼此独立,使得各个线程之间的代码是乱序执行的,同时他们可能会同时访问公共变量,导致数据的不一致。如图2.3中,第一行和第二行的结果正常,但是第三行和第四行是线程同时对nResValue进行操作,进程2在0的基础上减10,而进程1则在0的基础上加10,从而导致Result2=-10,Result1=10。这是个错误的结果。也就是说,在同一时刻,只能有一个线程对nResValue操作才是正确的,也只有这样才不会出现上面的情况。后面会专门讲这个问题——同步控制。2.2.2线程的创建、挂起、激活和终止•一个进程的主线程是由操作系统自动生成的,如果让一个主线程创建额外的子线程,可以通过CreateThread函数来完成。若线程创建成功,返回值为新线程的句柄;失败则返回NULL。•在创建的线程的时候,可以指定线程的初始状态。线程在创建的时候,有两种状态可以指定,执行状态和挂起状态。通过设置CreateThread的第五个参数可以设置线程的初始状态,当参数为0时,线程就会立即执行,而参数设置为CREATE_SUSPENDED时,线程创建后并不马上执行,而是被挂起。要想该线程能够执行,必须在主线程或者其他的线程里调用ResumeThread函数并传递给它调用CreateThread时返回的线程句柄来激活该进程。线程的挂起与激活•除了在创建线程的时候可以挂起线程,我们还可以通过函数SuspendThread来挂起线程,一个线程可以被挂起多次。线程可以自行暂停运行,但是不能自行恢复运行。如果一个线程被挂起n次,则该线程也必须被恢复n次才可能得以执行,该SuspendThread的声明如下:•DWORDSuspendThread(HANDLEhThread);其中hThread是线程句柄•激活一个线程时,系统会先检查线程挂起的次数,如果挂起的次数为0,则表示该线程并非处于挂起状态,否则,该线程的挂起次数值将被减1。ResumeThread函数很简单:•DWORDResumeThread(HANDLEhThread),其中hThread是线程句柄。线程的终止与休眠•当要中止一个线程的时候,类似于进程的中止。线程的终止有如下四种方式:(1)线程函数返回;(2)线程自身调用ExitThread函数即终止自己;(3)同一进程或其他进程的线程调用TerminateThread函数;(4)包含线程的进程终止。•VOIDSleep(DWORDdwMilliseconds);该函数可使线程暂停自己的运行,直到dwMilliseconds毫秒过去为止。它告诉系统,自身不想在某个时间段内被调度。2.2.3线程的优先级•线程是有一定的优先级,操作系统会根据线程的优先级进行调度,分配CPU时间片,一个线程的优先级首先属于一个类,其实就是一个进程,然后是在该类中的相对位置。线程的优先级的计算如下:线程优先级=进程类基本优先级+线程相对优先级•进程类的基本优先级包括:(1)实时:REALTIME_PRIORITY_CLASS;(2)高:HIGH_PRIORITY_CLASS;(3)高于正常:ABOVE_NORMAL_PRIORITY_CLASS;(4)正常:NORMAL_PRIORITY_CLASS;(5)低于正常:BELOW_NORMAL_PRIORITY_CLASS;(6)空闲:IDLE_PRIORITY_CLASS。实例图线程的相对优先级(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_PRIOTITY_CRITICAL。控制线程的优先级•通常,应用程序可以使用下列方法控制线程的相对优先级:•当使用CreateProcess时,可以指定进程的优先级;若未指定,缺省优先级为正常;•可以使用SetPriotityClass来改变进程的优先级。这将影响到进程内的所有线程的优先级,但是线程的相对优先级不会变;•可以通过SetThreadPriority来任何一个线程的优先级;•当一个线程首次被创建时,它的优先级类等同于它所属于的进程优先级类。2.3.1同步控制应用实例及意义•进程中的所有线程共享进程的虚拟地址空间,这意味着所有线程都可以访问进程中的资源,一方面,这种机制为我们的编程带来方便,但同时也会带来访问冲突,其结果会导致数据的错乱。线程的同步是为了协调多个线程的执行,保证数据完整性,以第二章代码“三线程同步”为例。•多线程编程一个最具挑战性的问题就是:如何让一个线程与另一个线程合作。•当程序1调用程序2时,程序1停下不动,直到程序2完成回到程序1来,程序1才继续下去,这就是所谓的同步。如果程序1调用程序2后,径自继续自己的下一个动作,那么两者之间就是异步。Win32API中的SendMassage()就是同步行为,而PostMassage()就是异步行为,如图所示同步与异步两个例子的比较2.3.2同步控制类型及应用条件•线程的同步是通过同步对象来实现的。同步对象是一个数据结构,用来协调多线程的执行,它可以被多个线程共享。•同步对象主要有五种:临界区域(CriticalSection)、互斥信号(Mutex)、信号量(Semaphone)、事件对象(Event)和互锁变量(Interlocked)。•两个重要的函数:监测单

1 / 47
下载文档,编辑使用

©2015-2020 m.777doc.com 三七文档.

备案号:鲁ICP备2024069028号-1 客服联系 QQ:2149211541

×
保存成功