目录
3.1 编写基本的 Win32 Consol Application
4.1 编写基本的 Win32 Consol Application
5.1 编写基本的 Win32 Consol Application
前言
本实验为课设内容,博客内容为部分报告内容,仅为大家提供参考,请勿直接抄袭,另外,本次实验所用平台是dev c++5.11
1 实验题目
实验一 Windows进程管理
2 实验目的
(1)学会使用 Dev-C++ 编写基本的 Win32 Consol Application(控制台应用程序)。
(2)通过创建进程、观察正在运行的进程和终止进程的程序设计和调试操作,进一步熟悉操作系统的进程概念,理解 Windows 进程的“一生”。
(3)通过阅读和分析实验程序,学习创建进程、观察进程、终止进程以及父子进程同步的基本程序设计方法。
3 实验内容
3.1 编写基本的 Win32 Consol Application
(1)步骤1:打开Dev-C++5.11 新建一个文件,命名为实验1-1,并保存为cpp文件。
(2)步骤2:将清单2-1的源代码复制到实验1-1.cpp文件中,并点击编译按钮将其编译成可执行文件。
(3)步骤3:进入到保存文件的目录下,右键,选择在终端打开,运行编译好的可执行文件,观察运行结果。
3.2 创建进程
3.2.1 步骤
(1)步骤1:打开Dev-C++5.11 新建一个文件,命名为实验1-2,并保存为cpp文件。
(2)步骤2:将清单2-2的源代码复制到实验1-2.cpp文件中,并点击编译按钮将其编译成可执行文件。
(3)步骤3:进入到保存文件的目录下,右键,选择在终端打开,运行编译好的可执行文件,观察运行结果。打开任务管理器,记录进程相关的行为属性。
(4)步骤4:在终端加入参数重新运行生成的可执行文件,观察运行结果。打开任务管理器,记录进程相关的行为属性。
(5)步骤5:修改清单 2-2 中的程序,将 nClone 的定义和初始化方法按程序注释中的修改方法进行修改,编译成可执行文件(执行前请先保存已经完成的工作)。再按步骤3中的方式运行。
3.2.2 关键代码
// 创建传递过来的进程的克隆过程并赋于其 ID 值
void StartClone(int nCloneID) {
...
创建进程:BOOL bCreateOK=::CreateProcess(
szFilename, // 产生这个 EXE 的应用程序的名称
szCmdLine, // 告诉其行为像一个子进程的标志
NULL, // 缺省的进程安全性
NULL, // 缺省的线程安全性
FALSE, // 不继承句柄
CREATE_NEW_CONSOLE, // 使用新的控制台
NULL, // 新的环境
NULL, // 当前目录
&si, // 启动信息
&pi) ; // 返回的进程信息
...
}
int main(int argc, char* argv[] ) {
...
克隆进程:const int c_nCloneMax=5;
if (nClone < c_nCloneMax) {
// 发送新进程的命令行和克隆号
StartClone(++nClone) ;
}
...
}
3.3 父子进程的简单通信及终止进程
3.3.1 步骤
(1)步骤1:打开Dev-C++5.11 新建一个文件,命名为实验1-3,并保存为cpp文件。
(2)步骤2:将清单2-3的源代码复制到实验1-3.cpp文件中,并点击编译按钮将其编译成可执行文件,再进入到保存文件的目录下,右键,选择在终端打开,运行编译好的可执行文件,观察运行结果。
(3)步骤3:修改清单 2-3 中的程序,并点击编译按钮将其编译成可执行文件并在终端运行(运行前请先保存已经完成的工作),观察运行结果。
(4)步骤4:修改清单 2-3 中第二处注释,并点击编译按钮将其编译成可执行文件并在终端运行,观察运行结果。
3.3.2 关键代码
void StartClone() {
...
//实验 2-3 步骤 3:将下句中的字符串 child 改为别的字符串,重新编译执行,执行前请先保存已经完成的工作
//主函数的参数也要一起改变,否则会一直生成父进程
sprintf(szCmdLine, "\"%s\" child" , szFilename) ;
...
}
int main(int argc, char* argv[] ) {
// 决定其行为是父进程还是子进程
if (argc>1 && :: strcmp(argv[1] , "child" )== 0) {
Child() ;
} else {
Parent() ;
}
}
4 实验结果与分析
4.1 编写基本的 Win32 Consol Application
按步骤3运行后的结果:
图1.1 实验1-1步骤3
4.2 创建进程
(1)按步骤2运行后的结果:
图1.2 实验1-2步骤3
(2)按步骤3,在终端加入参数‘4’会看到只有两个控制台,因为输入的参数覆盖了程序中nClone的值,结果如下:
图1.3 带参数后的结果
(3)执行步骤4后,按注释中,第一次nClone赋值的位置不会影响结果,但是第二次修改后,程序会一直弹出新的控制台,不能停下来,导致只能强行关机或者一直关闭所以控制台直到它自己不再打开新的控制台,所以就没有保存图片了,其是因为第二次修改的赋值将从父进程传递过来的值覆盖了,导致nClone一直小于5。
4.3 父子进程的简单通信及终止进程
(1)按步骤2运行后,可以看到有两个控制台窗口,具体如下面的图片所示,在父进程输入字符后,子进程会先结束,父进程再结束:
图1.4 父进程
图1.5 子进程
(2)执行步骤3后,程序会一直弹出新的控制台,不能停下来,导致只能强行关机或者一直关闭所以控制台直到它自己不再打开新的控制台,所以就没有保存图片了。但是如果修改了注释的地方后,把main函数的语句if (argc>1 && :: strcmp(argv[1] , "child" )== 0)中的字符串改为和修改的字符串一致,比如”china”,则不会一直弹出控制台。
(3)执行步骤4后,子进程会一闪而过,而且把0改成越来越大的数值之后,子进程停留的时间会越来越长。
5 代码
5.1 编写基本的 Win32 Consol Application
// hello 项目
# include <iostream>
using namespace std;
int main(void) {
std::cout << "Hello, Win32 Consol Application" << std :: endl ;
}
5.2 创建进程
#include <windows.h>
#include <iostream>
#include <stdio.h>
// 创建传递过来的进程的克隆过程并赋于其 ID 值
void StartClone(int nCloneID) {
// 提取用于当前可执行文件的文件名
TCHAR szFilename[MAX_PATH] ;
GetModuleFileName(NULL, szFilename, MAX_PATH) ;
// 格式化用于子进程的命令行并通知其 EXE 文件名和克隆 ID
TCHAR szCmdLine[MAX_PATH];
sprintf(szCmdLine,"\"%s\" %d",szFilename,nCloneID);
// 用于子进程的 STARTUPINFO 结构
STARTUPINFO si;
ZeroMemory(&si , sizeof(si) ) ;
si.cb = sizeof(si) ; // 必须是本结构的大小
// 返回的用于子进程的进程信息
PROCESS_INFORMATION pi;
// 利用同样的可执行文件和命令行创建进程,并赋于其子进程的性质
BOOL bCreateOK=::CreateProcess(
szFilename, // 产生这个 EXE 的应用程序的名称
szCmdLine, // 告诉其行为像一个子进程的标志
NULL, // 缺省的进程安全性
NULL, // 缺省的线程安全性
FALSE, // 不继承句柄
CREATE_NEW_CONSOLE, // 使用新的控制台,如果是NULL将会使用父进程窗口
NULL, // 新的环境
NULL, // 当前目录
&si, // 启动信息
&pi) ; // 返回的进程信息
// 对子进程释放引用
if (bCreateOK) {
CloseHandle(pi.hProcess) ;
CloseHandle(pi.hThread) ;
}
}
int main(int argc, char* argv[] ) {
// 确定派生出几个进程,及派生进程在进程列表中的位置
int nClone=0;
//std ::cout<<"aaa";
//修改语句:int nClone;
//第一次修改:nClone=0;
//nClone=0;
if (argc > 1) {
// 从第二个参数中提取克隆 ID
:: sscanf(argv[1] , "%d" , &nClone) ;
}
//第二次修改:nClone=0;
//nClone=0;
// 显示进程位置
std :: cout << "Process ID:" << :: GetCurrentProcessId()
<< ", Clone ID:" << nClone
<< std :: endl;
// 检查是否有创建子进程的需要
const int c_nCloneMax=5;
if (nClone < c_nCloneMax) {
// 发送新进程的命令行和克隆号
StartClone(++nClone) ;
}
// 等待响应键盘输入结束进程
getchar();
return 0;
}
5.3 父子进程的简单通信及终止进程
// procterm 项目
# include <windows.h>
# include <iostream>
# include <stdio.h>
static LPCTSTR g_szMutexName = "w2kdg.ProcTerm.mutex.Suicide" ;
// 创建当前进程的克隆进程的简单方法
void StartClone() {
// 提取当前可执行文件的文件名
TCHAR szFilename[MAX_PATH] ;
GetModuleFileName(NULL, szFilename, MAX_PATH) ;
// 格式化用于子进程的命令行,字符串“child”将作为形参传递给子进程的 main 函数
TCHAR szCmdLine[MAX_PATH] ;
//实验 2-3 步骤 3:将下句中的字符串 child 改为别的字符串,重新编译执行,执行前请先保存已经完成的工作
//主函数的参数也要一起改变,否则会一直生成父进程
sprintf(szCmdLine, "\"%s\" child" , szFilename) ;
// 子进程的启动信息结构
STARTUPINFO si;
ZeroMemory(&si,sizeof(si)) ;
si.cb = sizeof(si) ; // 应当是此结构的大小
// 返回的用于子进程的进程信息
PROCESS_INFORMATION pi;
// 用同样的可执行文件名和命令行创建进程,并指明它是一个子进程
BOOL bCreateOK=CreateProcess(
szFilename, // 产生的应用程序的名称 (本 EXE 文件)
szCmdLine, // 告诉我们这是一个子进程的标志
NULL, // 用于进程的缺省的安全性
NULL, // 用于线程的缺省安全性
FALSE, // 不继承句柄
CREATE_NEW_CONSOLE, //创建新窗口
NULL, // 新环境
NULL, // 当前目录
&si, // 启动信息结构
&pi ) ; // 返回的进程信息
// 释放指向子进程的引用
if (bCreateOK) {
CloseHandle(pi.hProcess) ;
CloseHandle(pi.hThread) ;
}
}
void Parent() {
// 创建“自杀”互斥程序体
HANDLE hMutexSuicide=CreateMutex(
NULL, // 缺省的安全性
TRUE, // 最初拥有的
g_szMutexName) ; // 互斥体名称
if (hMutexSuicide != NULL) {
// 创建子进程
std :: cout << "Creating the child process." << std :: endl;
StartClone() ;
// 指令子进程“杀”掉自身
std :: cout << "Telling the child process to quit. "<< std :: endl;
//等待父进程的键盘响应
getchar() ;
//释放互斥体的所有权,这个信号会发送给子进程的 WaitForSingleObject 过程
ReleaseMutex(hMutexSuicide) ;
// 消除句柄
CloseHandle(hMutexSuicide) ;
}
}
void Child() {
// 打开“自杀”互斥体
HANDLE hMutexSuicide = OpenMutex(
SYNCHRONIZE, // 打开用于同步
FALSE, // 不需要向下传递
g_szMutexName) ; // 名称
if (hMutexSuicide != NULL) {
// 报告我们正在等待指令
std :: cout <<"Child waiting for suicide instructions. " << std :: endl;
//子进程进入阻塞状态,等待父进程通过互斥体发来的信号
WaitForSingleObject(hMutexSuicide, INFINITE) ;//改成0子进程马上就结束了
//实验 2-3 步骤 4:将上句改为 WaitForSingleObject(hMutexSuicide, 0) ,重新编译执行
// 准备好终止,清除句柄
std :: cout << "Child quiting." << std :: endl;
CloseHandle(hMutexSuicide) ;
}
}
int main(int argc, char* argv[] ) {
// 决定其行为是父进程还是子进程
if (argc>1 && :: strcmp(argv[1] , "child" )== 0) {
Child() ;
} else {
Parent() ;
}
return 0;
}