Bootstrap

操作系统课设-Windows进程管理

一、实验一:

Windows进程管理

二、实验内容:

实验一包含三个小模块,一个一个分析

1. 清单1-1:

用devc++新建一个console application项目,运行指导书中的代码:

/*  实验一源程序 */
//清单1-1  一个简单的Windows控制台应用程序
// hello项目
# include <iostream>
int main()
{
	std::cout << "Hello, Win32 Consol Application" << std::endl;
	getchar();
}


显示内容:

 2. 清单1-2:

用devc++新建一个console application项目,运行指导书中的代码:

//清单1-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,						// 当前目录
        &si,						// 启动信息
        &pi) ;						// 返回的进程信息

    // 对子进程释放引用
    if (bCreateOK)
    {
        CloseHandle(pi.hProcess) ;
        CloseHandle(pi.hThread) ;
    }
}

int main(int argc, char* argv[] )
{
    // 确定派生出几个进程,及派生进程在进程列表中的位置
    int nClone=0;
//修改语句:int nClone;

//第一次修改:nClone=0;
    if (argc > 1)
    {
        // 从第二个参数中提取克隆ID
        :: sscanf(argv[1] , "%d" , &nClone) ; //用sscanf_s代替
    }

//第二次修改: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;
}

显示结果:

代码分析:

这段代码实现了一个带有克隆功能的进程程序,可以创建多个子进程。

首先,我们来看一下这段代码中使用到的一些函数:

  1. GetModuleFileName:获取当前可执行文件的完整路径和文件名。它的参数包括一个模块句柄(通常为NULL表示当前进程)、一个输出缓冲区、以及缓冲区大小。

  2. sprintf:将格式化字符串输出到指定的字符数组中。它的参数包括一个输出缓冲区、格式化字符串以及若干个待输出的值。

  3. ZeroMemory:将指定内存区域置零。它的参数包括一个指针和要置零的字节数。

  4. CreateProcess:创建一个新的进程,并返回该进程的句柄和线程句柄。它的参数包括要执行的可执行文件名、命令行参数、安全性描述、环境变量、是否继承其父进程的句柄等信息。

  5. CloseHandle:关闭指定的对象句柄。在进程退出后需要调用该函数释放已经打开的句柄。

接下来,我们来看一下代码的主要流程。首先,main函数会获取传递过来的参数(如果有),并解析出其中的克隆ID。然后,它会显示当前进程的ID和克隆ID,并检查是否需要创建子进程。如果克隆ID小于5,就会调用StartClone函数创建新的子进程,并将其克隆ID+1传递给StartClone函数。

StartClone函数负责创建子进程。它首先获取当前可执行文件的文件名,并格式化命令行参数,包括EXE文件名和克隆ID。然后,它使用CreateProcess函数创建一个新的进程,并指定要执行的EXE文件名和命令行参数等信息。最后,它关闭新进程的句柄和线程句柄。

总之,这段代码实现了一个简单的进程克隆程序,可以通过创建多个子进程来模拟并发执行。

 需要注意的是,这里如果将进行注释中的第二次修改,子进程将会无限产生,为什么呢?

首先我们要了解main函数中参数argc,argv的意思:argc表示参数的个数,argv是存储所有参数,其中argv[0]为当前文件地址。当在用CreateProcess函数创建子进程时,子进程的参数argv[]是用szCmdLine传过来的,从szCdLine赋值代码sprintf(szCmdLine,"\"%s\" %d",szFilename,nCloneID);可知,空格分开的两个参数分别文件地址和nCloneID,即argv[1]的值为子进程ID,用语句:: sscanf(argv[1] , "%d" , &nClone) ;子进程的nClone初始化,从而实现累加,在nClone加到5后不在产生子进程。而第二次修改时在赋初值之后将nClone归零,子进程不断产生。

 3. 清单1-3

用devc++新建一个console application项目,运行指导书中的代码:

//清单1-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] ;
//实验1-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) ;
//实验1-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)
    {
//    	std::cout<<argv[0]<<std::endl;
        Child() ;
    }
    else
    {
        Parent() ;
    }
return 0;

}

 显示结果:
产生两个进程

当父进程出入时,杀死子进程。

这是一个使用Windows上的互斥体实现进程间通信和终止的C++程序。以下是主要函数和API的解释:

API 函数

  • GetModuleFileName():获取当前可执行文件的完整路径和文件名。
  • sprintf():格式化字符串并将其写入缓冲区。
  • ZeroMemory():用零填充内存块。
  • CreateProcess():创建一个新的进程及其主线程。
  • CloseHandle():关闭对象的打开句柄。
  • CreateMutex():创建或打开一个命名或未命名的互斥体对象。
  • OpenMutex():打开一个现有的命名或未命名的互斥体对象。
  • WaitForSingleObject():等待指定的对象处于信号状态或超时间隔到期。
  • ReleaseMutex():释放指定的互斥体对象的所有权。

函数

  • StartClone():提取当前可执行文件的文件名,格式化命令行,并使用CreateProcess()创建子进程。
  • Parent():使用CreateMutex()创建“自杀”互斥体,使用StartClone()创建子进程,等待用户从键盘输入,使用ReleaseMutex()释放互斥体的所有权,并使用CloseHandle()关闭互斥体句柄和进程句柄。
  • Child():使用OpenMutex()打开“自杀”互斥体,使用WaitForSingleObject()等待父进程的信号,打印一条消息指示它已准备好终止自身,并使用CloseHandle()关闭互斥体句柄。
  • main():根据传递给程序的命令行参数决定是执行Parent()还是Child()函数。

在这个程序中,“自杀”互斥体用于向子进程发出终止自身的信号。父进程创建互斥体,创建子进程,等待用户从键盘输入,释放互斥体的所有权。子进程打开互斥体,等待父进程的信号,终止自身,并关闭互斥体句柄。

总的来说,这个程序演示了如何使用互斥体对象在Windows上创建和通信子进程和父进程之间的方法。

这里如果将WaitForSingleObject(hMutexSuicide, INFINITE) ;的INFINITE改成0,子进程将会被立即杀死,原因是子进程超时间隔到期。

;