[关闭]
@1405010304geshuaishuai 2016-04-21T09:27:23.000000Z 字数 5134 阅读 2914

实验五---Windows 进程管理

windows 进程管理


作者:葛帅帅

学号:1405010304

班级:三班


1、实验目的

(1)学会使用VC 编写基本的Win32 Consol Application(控制台应用程序)。

(2)通过创建进程、观察正在运行的进程和终止进程的程序设计和调试操作,进一步熟悉操作系统的进程概念,理解Windows 进程的“一生”。

(3)通过阅读和分析实验程序,学习创建进程、观察进程、终止进程以及父子进程同步的基本程序设计方法。

2、背景知识

Windows 所创建的每个进程都从调用CreateProcess() API 函数开始,该函数的任务是在对象管理器子系统内初始化进程对象。每一进程都以调用ExitProcess() 或TerminateProcess() API 函数终止。通常应用程序的框架负责调用 ExitProcess() 函数。对于C++ 运行库来说,这一调用发生在应用程序的main() 函数返回之后。

3、实验内容和步骤

(1)编写基本的Win32 Consol Application

步骤1:登录进入Windows 系统,启动VC++ 6.0。
步骤2:在“FILE”菜单中单击“NEW”子菜单,在“projects”选项卡中选择“Win32 ConsolApplication”,然后在“Project name”处输入工程名,在“Location” 处输入工程目录。创建一个新的控制台应用程序工程。
步骤3:在“FILE”菜单中单击“NEW”子菜单,在“Files”选项卡中选择“C++ Source File”,
然后在“File” 处输入C/C++源程序的文件名。
步骤4:将清单1-1 所示的程序清单复制到新创建的C/C++源程序中。编译成可执行文件。
步骤5:在“开始”菜单中单击“程序”-“附件”-“命令提示符”命令,进入Windows“命
令提示符”窗口,然后进入工程目录中的debug 子目录,执行编译好的可执行程序,列出运行结果如图5-1.

  1. 清单1-1 一个简单的Windows 控制台应用程序
  2. // hello 项目
  3. # include <iostream>
  4. void main()
  5. {
  6. std::cout << Hello, Win32 Consol Application << std :: endl ;
  7. }

result1

(2)创建进程

本实验显示了创建子进程的基本框架。该程序只是再一次地启动自身,显示它的系统进程ID和它在进程列表中的位置。
步骤1:创建一个“Win32 Consol Application”工程,然后拷贝清单1-2 中的程序,编译成可执行文件。
步骤2:在“命令提示符”窗口运行步骤1 中生成的可执行文件,列出运行结果(见图5-2)。按下ctrl+alt+del,调用windows的任务管理器,记录进程相关的行为属性(见图5-3)。
步骤3:在“命令提示符”窗口加入参数重新运行生成的可执行文件,列出运行结果(见图5-4)。按下ctrl+alt+del,调用windows 的任务管理器,记录进程相关的行为属性。
步骤4:修改清单1-2 中的程序,将nClone 的定义和初始化方法按程序注释中的修改方法进行修改,编译成可执行文件(执行前请先保存已经完成的工作)。再按步骤2 中的方式运行,看看结果会有什么不一样。

  1. 清单1-2 创建子进程
  2. #include <windows.h>
  3. #include <iostream>
  4. #include <stdio.h>
  5. // 创建传递过来的进程的克隆过程并赋于其ID 值
  6. void StartClone(int nCloneID)
  7. {
  8. // 提取用于当前可执行文件的文件名
  9. TCHAR szFilename[MAX_PATH] ;
  10. GetModuleFileName(NULL, szFilename, MAX_PATH) ;
  11. // 格式化用于子进程的命令行并通知其EXE 文件名和克隆ID
  12. TCHAR szCmdLine[MAX_PATH];
  13. sprintf(szCmdLine,"\"%s\" %d",szFilename,nCloneID);
  14. // 用于子进程的STARTUPINFO 结构
  15. STARTUPINFO si;
  16. ZeroMemory(&si , sizeof(si) ) ;
  17. si.cb = sizeof(si) ; // 必须是本结构的大小
  18. // 返回的用于子进程的进程信息
  19. PROCESS_INFORMATION pi;
  20. // 利用同样的可执行文件和命令行创建进程,并赋于其子进程的性质
  21. BOOL bCreateOK=::CreateProcess(
  22. szFilename, // 产生这个EXE 的应用程序的名称
  23. szCmdLine, // 告诉其行为像一个子进程的标志
  24. NULL, // 缺省的进程安全性
  25. NULL, // 缺省的线程安全性
  26. FALSE, // 不继承句柄
  27. CREATE_NEW_CONSOLE, // 使用新的控制台
  28. NULL, // 新的环境
  29. NULL, // 当前目录
  30. &si, // 启动信息
  31. &pi) ; // 返回的进程信息
  32. // 对子进程释放引用
  33. if (bCreateOK)
  34. {
  35. CloseHandle(pi.hProcess) ;
  36. CloseHandle(pi.hThread) ;
  37. }
  38. }
  39. int main(int argc, char* argv[] )
  40. {
  41. // 确定派生出几个进程,及派生进程在进程列表中的位置
  42. int nClone=0;
  43. //修改语句:int nClone;
  44. //第一次修改:nClone=0;
  45. if (argc > 1)
  46. {
  47. // 从第二个参数中提取克隆ID
  48. :: sscanf(argv[1] , "%d" , &nClone) ;
  49. }
  50. //第二次修改:nClone=0;
  51. // 显示进程位置
  52. std :: cout << "Process ID:" << :: GetCurrentProcessId()
  53. << ", Clone ID:" << nClone
  54. << std :: endl;
  55. // 检查是否有创建子进程的需要
  56. const int c_nCloneMax=5;
  57. if (nClone < c_nCloneMax)
  58. {
  59. // 发送新进程的命令行和克隆号
  60. StartClone(++nClone) ;
  61. }
  62. // 等待响应键盘输入结束进程
  63. getchar();
  64. return 0;
  65. }

result2
result3
result4

(3) 父子进程的简单通信及终止进程

步骤1:创建一个“Win32ConsolApplication”工程,然后拷贝清单1-3中的程序,编译成可执行文件。
步骤2:在VC 的工具栏单击“Execute Program”(执行程序) 按钮,或者按Ctrl + F5键,或者在“命令提示符”窗口运行步骤1 中生成的可执行文件,列出运行结果(见图5-5)。
步骤3:按源程序中注释中的提示,修改源程序1-3,编译执行(执行前请先保存已经完成的工作),列出运行结果(见图5-6)。在程序中加入跟踪语句,或调试运行程序,同时参考MSDN中的帮助文件CreateProcess()的使用方法,理解父子进程如何传递参数。给出程序执行过程的大概描述。
步骤4:按源程序中注释中的提示,修改源程序1-3,编译,列出运行结果(见图5-7)。
步骤5:参考MSDN 中的帮助文件CreateMutex() 、OpenMutex() 、ReleaseMutex()和WaitForSingleObject()的使用方法,理解父子进程如何利用互斥体进行同步的。给出父子进程同步过程的一个大概描述。

  1. 清单1-3 父子进程的简单通信及终止进程的示例程序
  2. // procterm 项目
  3. # include <windows.h>
  4. # include <iostream>
  5. # include <stdio.h>
  6. static LPCTSTR g_szMutexName = "w2kdg.ProcTerm.mutex.Suicide" ;
  7. // 创建当前进程的克隆进程的简单方法
  8. void StartClone()
  9. {
  10. // 提取当前可执行文件的文件名
  11. TCHAR szFilename[MAX_PATH] ;
  12. GetModuleFileName(NULL, szFilename, MAX_PATH) ;
  13. // 格式化用于子进程的命令行,字符串“child”将作为形参传递给子进程的main 函数
  14. TCHAR szCmdLine[MAX_PATH] ;
  15. //实验1-3 步骤3:将下句中的字符串child 改为别的字符串,重新编译执行,执行前请先保存已经
  16. 完成的工作
  17. sprintf(szCmdLine, "\"%s\"child" , szFilename) ;
  18. // 子进程的启动信息结构
  19. STARTUPINFO si;
  20. ZeroMemory(&si,sizeof(si)) ;
  21. si.cb = sizeof(si) ; // 应当是此结构的大小
  22. // 返回的用于子进程的进程信息
  23. PROCESS_INFORMATION pi;
  24. // 用同样的可执行文件名和命令行创建进程,并指明它是一个子进程
  25. BOOL bCreateOK=CreateProcess(
  26. szFilename, // 产生的应用程序的名称 (本EXE 文件)
  27. szCmdLine, // 告诉我们这是一个子进程的标志
  28. NULL, // 用于进程的缺省的安全性
  29. NULL, // 用于线程的缺省安全性
  30. FALSE, // 不继承句柄
  31. CREATE_NEW_CONSOLE, //创建新窗口
  32. NULL, // 新环境
  33. NULL, // 当前目录
  34. &si, // 启动信息结构
  35. &pi ) ; // 返回的进程信息
  36. // 释放指向子进程的引用
  37. if (bCreateOK)
  38. {
  39. CloseHandle(pi.hProcess) ;
  40. CloseHandle(pi.hThread) ;
  41. }
  42. }
  43. void Parent()
  44. {
  45. // 创建“自杀”互斥程序体
  46. HANDLE hMutexSuicide=CreateMutex(
  47. NULL, // 缺省的安全性
  48. TRUE, // 最初拥有的
  49. g_szMutexName) ; // 互斥体名称
  50. if (hMutexSuicide != NULL)
  51. {
  52. // 创建子进程
  53. std :: cout << "Creating the child process." << std :: endl;
  54. StartClone() ;
  55. // 指令子进程“杀”掉自身
  56. std :: cout << "Telling the child process to quit. "<< std :: endl;
  57. //等待父进程的键盘响应
  58. getchar() ;
  59. //释放互斥体的所有权,这个信号会发送给子进程的WaitForSingleObject 过程
  60. ReleaseMutex(hMutexSuicide) ;
  61. // 消除句柄
  62. CloseHandle(hMutexSuicide) ;
  63. }
  64. }
  65. void Child()
  66. {
  67. // 打开“自杀”互斥体
  68. HANDLE hMutexSuicide = OpenMutex(
  69. SYNCHRONIZE, // 打开用于同步
  70. FALSE, // 不需要向下传递
  71. g_szMutexName) ; // 名称
  72. if (hMutexSuicide != NULL)
  73. {
  74. // 报告我们正在等待指令
  75. std :: cout <<"Child waiting for suicide instructions. " << std :: endl;
  76. //子进程进入阻塞状态,等待父进程通过互斥体发来的信号
  77. WaitForSingleObject(hMutexSuicide, INFINITE) ;
  78. //实验1-3 步骤4:将上句改为WaitForSingleObject(hMutexSuicide, 0) ,重新编译执行
  79. // 准备好终止,清除句柄
  80. std :: cout << "Child quiting." << std :: endl;
  81. CloseHandle(hMutexSuicide) ;
  82. }
  83. }
  84. int main(int argc, char* argv[] )
  85. {
  86. // 决定其行为是父进程还是子进程
  87. if (argc>1 && :: strcmp(argv[1] , "child" )== 0)
  88. {
  89. Child() ;
  90. }
  91. else
  92. {
  93. Parent() ;
  94. }
  95. return 0;
  96. }

result5
result6
result7

Q:给出父子进程同步过程的一个大概描述。

A:把某进程未获得合作进程发来消息之前,该进程等待,消息到来之后方可继续执行的进程合作关系,称为进程的同步。为了描述进程的互斥与同步,我们引入临界资源和临界区的概念。临界资源就是一次仅允许一个进程使用的共享资源。临界区就是一个进程中访问临界资源的那段程序。进程的互斥就可描述为:两个进程不能同时进入访问同一临界资源的临界区。为此,必须有软件算法或同步机构来协调它们,协调的准则是:(1)当有若干进程欲进入临界区时,它们不应相互阻塞致使彼此都不能进入临界区,而应在有限时间内使一进程进入临界区;(2)每次至多有一个进程处于临界区;(3)进程仅在临界区内逗留有限时间。遵循以上准则,得到临界区的调用原则是:(1)当无一进程处于临界区内时,允许一进程立即进入;(2)已有进程在临界区时,其他试图进入临界区的进程必须等待;(3)一进程离开监界区时,若有等待者,则允许其中一个进入临界区。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注