ImageVerifierCode 换一换
格式:DOCX , 页数:16 ,大小:24.67KB ,
资源ID:7579757      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/7579757.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(VC++中进程与多进程管理的方法.docx)为本站会员(b****6)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

VC++中进程与多进程管理的方法.docx

1、VC+中进程与多进程管理的方法 VC+中进程与多进程管理的方法进程是当前操作系统下一个被加载到内存的、正在运行的应用程序的实例。每一个进程都是由内核对象和地址空间所组成的,内核对象可以让系统在其内存放有关进程的统计信息并使系统能够以此来管理进程,而地址空间则包括了所有程序模块的代码和数据以及线程堆栈、堆分配空间等动态分配的空间。进程仅仅是一个存在,是不能独自完成任何操作的,必须拥有至少一个在其环境下运行的线程,并由其负责执行在进程地址空间内的代码。在进程启动的同时即同时启动了一个线程,该线程被称作主线程或是执行线程,由此线程可以继续创建子线程。如果主线程退出,那么进程也就没有存在的可能了,系统

2、将自动撤消该进程并完成对其地址空间的释放。加载到进程地址空间的每一个可执行文件或动态链接库文件的映象都会被分配一个与之相关联的全局唯一的实例句柄(Hinstance)。该实例句柄实际是一个记录有进程加载位置的基本内存地址。进程的实例句柄在程序入口函数WinMain()中通过第一个参数HINSTANCE hinstExe传递,其实际值即为进程所使用的基本地址空间的地址。对于VC+链接程序所链接产生的程序,其默认的基本地址空间地址为0x00400000,如没有必要一般不要修改该值。在程序中,可以通过GetModuleHandle()函数得到指定模块所使用的基本地址空间。子进程的创建进程的创建通过C

3、reateProcess()函数来实现,CreateProcess()通过创建一个新的进程及在其地址空间内运行的主线程来启动并运行一个新的程序。具体的,在执行CreateProcess()函数时,首先由操作系统负责创建一个进程内核对象,初始化计数为1,并立即为新进程创建一块虚拟地址空间。随后将可执行文件或其他任何必要的动态链接库文件的代码和数据装载到该地址空间中。在创建主线程时,也是首先由系统负责创建一个线程内核对象,并初始化为1。最后启动主线程并执行进程的入口函数WinMain(),完成对进程和执行线程的创建。CreateProcess()函数的原型声明如下:BOOL CreateProce

4、ss(LPCTSTR lpApplicationName, / 可执行模块名LPTSTR lpCommandLine, / 命令行字符串LPSECURITY_ATTRIBUTES lpProcessAttributes, / 进程的安全属性LPSECURITY_ATTRIBUTES lpThreadAttributes, / 线程的安全属性BOOL bInheritHandles, / 句柄继承标志DWORD dwCreationFlags, / 创建标志LPVOID lpEnvironment, / 指向新的环境块的指针LPCTSTR lpCurrentDirectory, / 指向当前目录

5、名的指针LPSTARTUPINFO lpStartupInfo, / 指向启动信息结构的指针LPPROCESS_INFORMATION lpProcessInformation / 指向进程信息结构的指针); 在程序设计时,某一个具体的功能模块可以通过函数或是线程等不同的形式来实现。对于同一进程而言,这些函数、线程都是存在于同一个地址空间下的,而且在执行时,大多只对与其相关的一些数据进行处理。如果算法存在某种错误,将有可能破坏与其同处一个地址空间的其他一些重要内容,这将造成比较严重的后果。为保护地址空间中的内容可以考虑将那些需要对地址空间中的数据进行访问的操作部分放到另外一个进程的地址空间中运

6、行,并且只允许其访问原进程地址空间中的相关数据。具体的,可在进程中通过CreateProcess()函数去创建一个子进程,子进程在全部处理过程中只对父进程地址空间中的相关数据进行访问,从而可以保护父进程地址空间中与当前子进程执行任务无关的全部数据。对于这种情况,子进程所体现出来的作用同函数和线程比较相似,可以看成是父进程在运行期间的一个过程。为此,需要由父进程来掌握子进程的启动、执行和退出。下面这段代码即展示了此过程:/ 临时变量CString sCommandLine;char cWindowsDirectoryMAX_PATH;char cCommandLineMAX_PATH;DWORD

7、 dwExitCode;PROCESS_INFORMATION pi;STARTUPINFO si = sizeof(si);/ 得到Windows目录GetWindowsDirectory(cWindowsDirectory, MAX_PATH);/ 启动记事本程序的命令行sCommandLine = CString(cWindowsDirectory) + NotePad.exe;:strcpy(cCommandLine, sCommandLine);/ 启动记事本作为子进程BOOL ret = CreateProcess(NULL, cCommandLine, NULL, NULL, F

8、ALSE, 0, NULL, NULL, &si, &pi);if (ret) / 关闭子进程的主线程句柄CloseHandle(pi.hThread);/ 等待子进程的退出WaitForSingleObject(pi.hProcess, INFINITE);/ 获取子进程的退出码GetExitCodeProcess(pi.hProcess, &dwExitCode);/ 关闭子进程句柄CloseHandle(pi.hProcess); 此段代码首先通过CreateProcess()创建Windows自带的“记事本”程序为子进程,子进程启动后父进程通过WaitForSingleObject()

9、函数等待其执行的结束,在子进程没有退出前父进程是一直处于阻塞状态的,这里子进程的作用同单线程中的函数类似。一旦子进程退出,WaitForSingleObject()函数所等待的pi.hProcess对象将得到通知,父进程将得以继续,如有必要可以通过GetExitCodeProcess()来获取子进程的退出代码。相比而言,更多的情况是父进程在启动完子进程后就再不与其进行任何数据交换和通讯,由其创建的子进程的执行成功与否均与父进程无关。许多大型软件在设计时也多采用了这类思想,将某些功能完全通过独立的应用程序来完成,当需要执行某操作时只要通过主程序启动相应的子进程即可,具体的处理工作均由子进程去完成

10、。这类子进程的创建过程更为简单,例如对于上面那段代码只需去除对子进程句柄pi.hProcess的等待即可:BOOL ret = CreateProcess(NULL, cCommandLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);if (ret) / 关闭子进程的主线程句柄CloseHandle(pi.hThread);/ 关闭子进程句柄CloseHandle(pi.hProcess); 可以通过dwCreationFlags参数在创建进程时设置子进程的优先级。前面的示例代码在创建子进程时使用的均是默认的优先级,如果要将优先级设置为高,可以

11、修改如下:BOOL ret = CreateProcess(NULL, cCommandLine, NULL, NULL, FALSE, HIGH_PRIORITY_CLASS, NULL, NULL, &si, &pi); 如果在进程创建时没有特别设置优先级,可以通过SetPriorityClass()函数来动态设定,该函数需要待操作进程的句柄和优先级标识符作为入口参数,函数原型为:BOOL SetPriorityClass(HANDLE hProcess, DWORD dwPriorityClass); 对于前面没有设定优先级的例子代码,可以在子进程启动后由父进程来动态改变其优先级设置:S

12、etPriorityClass(pi.hProcess, HIGH_PRIORITY_CLASS); 或是由子进程在其启动后自行改变优先级设置,需要注意的是这时进程句柄应设置为子进程自身的句柄,可通过GetCurrentProcess()函数来获取:HANDLE hProcess = GetCurrentProcess();SetPriorityClass(hProcess, HIGH_PRIORITY_CLASS); 进程的互斥运行正常情况下,一个进程的运行一般是不会影响到其他正在运行的进程的。但是对于某些有特殊要求的如以独占方式使用串行口等硬件设备的程序就要求在其进程运行期间不允许其他试图

13、使用此端口设备的程序运行的,而且此类程序通常也不允许运行同一个程序的多个实例。这就引出了进程互斥的问题。实现进程互斥的核心思想比较简单:进程在启动时首先检查当前系统是否已经存在有此进程的实例,如果没有,进程将成功创建并设置标识实例已经存在的标记。此后再创建进程时将会通过该标记而知晓其实例已经存在,从而保证进程在系统中只能存在一个实例。具体可以采取内存映射文件、有名事件量、有名互斥量以及全局共享变量等多种方法来实现。下面就分别对其中具有代表性的有名互斥量和全局共享变量这两种方法进行介绍:/ 创建互斥量HANDLE m_hMutex = CreateMutex(NULL, FALSE, Sampl

14、e07);/ 检查错误代码if (GetLastError() = ERROR_ALREADY_EXISTS) / 如果已有互斥量存在则释放句柄并复位互斥量CloseHandle(m_hMutex);m_hMutex = NULL;/ 程序退出return FALSE; 上面这段代码演示了有名互斥量在进程互斥中的用法。代码的核心是CreateMutex()对有名互斥量的创建。CreateMutex()函数可用来创建一个有名或无名的互斥量对象,其函数原型为:HANDLE CreateMutex(LPSECURITY_ATTRIBUTES lpMutexAttributes, / 指向安全属性的指

15、针BOOL bInitialOwner, / 初始化互斥对象的所有者LPCTSTR lpName / 指向互斥对象名的指针); 如果函数成功执行,将返回一个互斥量对象的句柄。如果在CreateMutex()执行前已经存在有相同名字的互斥量,函数将返回这个已经存在互斥量的句柄,并且可以通过GetLastError()得到错误代码ERROR_ALREADY_EXIST。可见,通过对错误代码ERROR_ALREADY_EXIST的检测可以实现CreateMutex()对进程的互斥。使用全局共享变量的方法则主要是在MFC框架程序中通过编译器来实现的。通过#pragma data_seg预编译指令创建一

16、个新节,在此节中可用volatile关键字定义一个变量,而且必须对其进行初始化。Volatile关键字指定了变量可以为外部进程访问。最后,为了使该变量能够在进程互斥过程中发挥作用,还要将其设置为共享变量,同时允许具有读、写访问权限。这可以通过#pragma comment预编译指令来通知编译器。下面给出使用了全局变量的进程互斥代码清单:#pragma data_seg(Shared) int volatile g_lAppInstance =0;#pragma data_seg()#pragma comment(linker,/section:Shared,RWS)if(+g_lAppInst

17、ance1)return FALSE; 此段代码的作用是在进程启动时对全局共享变量g_nAppInstancd 加1 ,如果发现其值大于1,那么就返回FALSE以通知进程结束。这里需要特别指出的是,为了使以上两段代码能够真正起到对进程互斥的作用,必须将其放置在应用程序的入口代码处,即应用程序类的初始化实例函数InitInstance()的开始处。结束进程进程只是提供了一段地址空间和内核对象,其运行是通过在其地址空间内的主线程来体现的。当主线程的进入点函数返回时,进程也就随之结束。这种进程的终止方式是进程的正常退出,进程中的所有线程资源都能够得到正确的清除。除了这种进程的正常推出方式外,有时还需

18、要在程序中通过代码来强制结束本进程或其他进程的运行。ExitProcess()函数即可在进程中的某个线程中使用,并将立即终止本进程的运行。ExitProcess()函数原型为:VOID ExitProcess(UINT uExitCode); 其参数uExitCode为进程设置了退出代码。该函数具有强制性,在执行完毕后进程即已经被结束,因此位于其后的任何代码将不能被执行。虽然ExitProcess()函数可以在结束进程的同时通知与其相关联的动态链接库,但是由于它的这种执行的强制性,使得ExitProcess()函数在使用上将存在有安全隐患。例如,如果在程序调用ExitProcess()函数之前

19、曾用new操作符申请过一段内存,那么将会由于ExitProcess()函数的强制性而无法通过delete操作符将其释放,从而造成内存泄漏。有鉴于ExitProcess()函数的强制性和不安全性,在使用时一定要引起注意。ExitProcess()只能强制执行本进程的退出,如果要在一个进程中强制结束其他的进程就要用TerminateProcess()来实现。与ExitProcess()不同,TerminateProcess()函数执行后,被终止的进程是不会得到任何关于程序退出的通知的。也就是说,被终止的进程是无法在结束运行前进行退出前的收尾工作的。所以,通常只有在其他任何方法都无法迫使进程退出时才

20、会考虑使用TerminateProcess()去强制结束进程的。下面给出TerminateProcess()的函数原型:BOOL TerminateProcess(HANDLE hProcess, UINT uExitCode); 参数hProcess和uExitCode分别为进程句柄和退出代码。如果被结束的是本进程,可以通过GetCurrentProcess()获取到句柄。TerminateProcess()是异步执行的,在调用返回后并不能确定被终止进程是否已经真的退出,如果调用TerminateProcess()的进程对此细节关心,可以通过WaitForSingleObject()来等待进

21、程的真正结束。小结多进程是多任务管理中的重要内容,文中上述部分对其基本概念和主要的技术如子进程的创建与结束、进程间的互斥运行等做了较详细的介绍。通过本文读者应能对多进程管理有一个初步的认识。 进程控制简单的说相当于在一个程序中执行另一个程序,你可以把它想象成在 Dos 下用 int 21h/4bh 功能来执行另外一个程序,如果单从执行另一个程序的目的来讲,在 Windows 中有不少方法,如使用 ShellExecute 等,但这些 Api 仅仅是“执行”而已,进程控制的意义在于可以创建一个进程,并可以通过进程句柄结束进程,同样你也可以通过进程句柄来跟踪程序,还可以用 ReadProcessM

22、emory 和 WriteProcessMemory 来读写子进程的内存空间。进程控制要使用的相关 API 有下面这些:创建进程的函数为CreateProcess,该函数比较复杂,共有十个参数,但有个好消息是使用时大部分可以用 NULL。BOOL CreateProcess( LPCTSTR lpApplicationName, / 执行程序文件名LPTSTR lpCommandLine, / 参数行 LPSECURITY_ATTRIBUTES lpProcessAttributes, / 进程安全参数LPSECURITY_ATTRIBUTES lpThreadAttributes, / 线程

23、安全参数BOOL bInheritHandles, / 继承标记DWORD dwCreationFlags, / 创建标记LPVOID lpEnvironment, / 环境变量LPCTSTR lpCurrentDirectory, / 运行该子进程的初始目录LPSTARTUPINFO lpStartupInfo, / 创建该子进程的相关参数 LPPROCESS_INFORMATION lpProcessInformation / 创建后用于被创建子进程的信息);各个参数的说明如下: lpApplicationName:为执行程序的文件名,你也可以把执行文件名包括在下一个参数 lpComman

24、dLine 中,然后把该参数置为NULL。 lpCommandLine:为参数行,如果无参数可以为NULL,在有参数传递给进程时可以如下设置:lpApplicationName=文件名;lpCommandLine=参数,或者 lpApplicationName=NULL;lpCommandLine=文件名 + 参数。 lpProcessAttributes,lpThreadAttributes:分别描述了创建的进程和线程安全属性,如果使用NULL表示使用默认的安全描述。 bInheritHandles:表示当前进程中的打开的句柄是否能够被创建的子进程所继承。 dwCreationFlags:表

25、示创建标记,通过该标记可以设置进程的创建状态和优先级别。常用的有下面的标记: CREATE_NEW_CONSOLE:为子进程创建一个新的控制台。 CREATE_SUSPENDED:子进程在创建时为挂起状态。如果指定了这个参数,那么执行 CreateProcess 后进程只是被装入内存,但不是马上开始执行,而是必须等主程序调用 ResumeThread 后才继续执行。HIGH_PRIORITY_CLASS/NORMAL_PRIORITY_CLASS:高/普通优先级别。 lpEnvironment:表示子进程所使用的环境变量,如果为NULL,则表示与当前进程使用相同的环境变量。 lpCurrent

26、Directory:表示子进程运行的初始目录。 lpStartupInfo:STARTUPINFO 结构,用于在创建子进程时设置各种属性。 lpProcessInformation:PROCESS_INFORMATION 结构,用来在进程创建后接收相关信息,该结构由系统填写。调用 CreateProcess 函数有三个参数是必需的,一在 lpApplicationName 或 lpCommandLine 指定文件名,二是 lpStartupInfo 结构,三是 PROCESS_INFORMATION 结构,因为 PROCESS_INFORMATION 结构返回了进程建立后的句柄,以后的一切操作

27、将要用到这些返回的句柄,它是由系统填写的,结构说明如下:typedef struct _PROCESS_INFORMATION HANDLE hProcess; /进程句柄HANDLE hThread; /进程的主线程句柄DWORD dwProcessId; /进程IDDWORD dwThreadId; /进程的主线程ID PROCESS_INFORMATION;另外还有一个关键的结构 STARTUPINFO,该结构定义如下:typedef struct STARTUPINFO DWORD cb; /结构长度LPTSTR lpReserved; /保留LPTSTR lpDesktop; /保留

28、LPTSTR lpTitle; /如果为控制台进程则为显示的标题DWORD dwX; /窗口位置DWORD dwY; /窗口位置DWORD dwXSize; /窗口大小DWORD dwYSize; /窗口大小DWORD dwXCountChars; /控制台窗口字符号宽度DWORD dwYCountChars; /控制台窗口字符号高度DWORD dwFillAttribute; /控制台窗口填充模式DWORD dwFlags; /创建标记WORD wShowWindow; /窗口显示标记,如同ShowWindow中的标记WORD cbReserved2; /LPBYTE lpReserved2

29、; /HANDLE hStdInput; /标准输入句柄HANDLE hStdOutput; /标准输出句柄HANDLE hStdError; /标准错误句柄 STARTUPINFO, *LPSTARTUPINFO;结构中 dwFlags 指定了其它的一些字段是否有效,如:dwFlags包含 STARTF_USESIZE 表示dwXSize和dwYSize有效,包含STARTF_USEPOSITION表示dwX和dwY有效,等等。如果不是有特殊的要求,我们不用自己去填写这个结构,只需用 GetStartupInfo 让 Windows 为你填写好了,这样,建立一个进程的语句就是:.stStar

30、tUp STARTUPINFO stProcInfo PROCESS_INFORMATION stProcInfo PROCESS_INFORMATION .invoke GetStartupInfo,addr stStartUpinvoke CreateProcess,NULL,addr szFileName,NULL,NULL,NULL,NORMAL_PRIORITY_CLASS,NULL,NULL,offset stStartUp,offset stProcInfo.如果成功的话,eax 将返回非零值,注意返回在 PROCESS_INFORMATION 结构中的 hProcess,以后很

31、多的操作都要用到它。强制结束一个进程的 API 为 TerminateProcessBOOL TerminateProcess(HANDLE hProcess, / 进程句柄UINT uExitCode / 退出代码 );你可以使用语句 invoke TerminateProcess,structProcInfo.hProcess,0 来结束进程,要注意的是如果可能的话,尽量不要在程序中强制结束别的进程,因为使用 TerminateProcess 结束的进程,它装载的 dll 不能被正确卸载。这样可能会引起系统资源的无效占用。最好的办法在进程中自己使用 ExitProcess 退出。查询一个进程状态的 API 为 GetExitCodeProcess。BOOL GetExitCodeProcess(HANDLE hProcess, / handle to the process LPDWORD lpExitCode / address to receive termination status

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1