操作系统课程设计父子进程的简单通信以及终止进程源码解析

这里的父子进程通信,其实说白了就是一个上课时候学的PV操作,是一个进程的同步,而终止进程,基本上就是关闭创建子进程的句柄,回收给子进程的资源,从而关闭这个进程。其中出现了以下的问题;

在没有修改之前:

wsprintf(szCmdLine, "\"%s\" chid" , szFilename) ;
	//将szFilename 和 nCloneID 以规定的格式写入到szCmdLine中

	STARTUPINFO si;
	ZeroMemory(&si, sizeof(si));
	si.cb = sizeof(si);

	PROCESS_INFORMATION pi;   //这个结构体将存储CreateProcess返回的创建新的进程的一些信息以及他的主要线程
	BOOL bCreateOK = ::CreateProcess(
		szFilename,
		szCmdLine,
		NULL,
		NULL,
		FALSE,
		CREATE_NEW_CONSOLE,
		NULL,
		NULL,
		&si,
		&pi
		);
在利用createprocess函数创建进程的时候,在命令行中就需要szCmdLine这个变量才作为argv中的的参数来创建这个子进程。由于两个参数是分开的,所以在wsprintf函数里面的"\"%s\" chid"这个部分,%s这里面要填入的是可执行文件的路径,而child是为了要创建子进程。所以两个参数之间要添加上空格才可以。


修改第一次之后:

wsprintf(szCmdLine, "\"%s\" chid" , szFilename) ;将此函数的child部分改为一个其他的字符串,那么在创建进程的时候,第二个参数就不再是child,很自然,在创建子进程的时候,进入的不再是child函数,而是parent函数,所以,程序就在不断的创建子进程,没有停止的趋势。创建进程函数的大致工作原理如下:


BOOL CreateProcess( 
  LPCWSTR pszImageName, 
  LPCWSTR pszCmdLine, 
  LPSECURITY_ATTRIBUTES psaProcess, 
  LPSECURITY_ATTRIBUTES psaThread, 
  BOOL fInheritHandles, 
  DWORD fdwCreate, 
  LPVOID pvEnvironment, 
  LPWSTR pszCurDir, 
  LPSTARTUPINFOW psiStartInfo, 
  LPPROCESS_INFORMATION pProcInfo
); 

主要是第一和第二个参数,一个是 是可执行模块的绝对路径,也可以是相对路径,在后一种情况下,函数使用当前驱动器和目录建立可执行模块的路径。,第二个是 指定将被运行的模块的命令行。也就是说第一个参数是找到要创建新进程运行可执行文件的具体位置,第二个就是命令行参数,来执行这个文件,创建一个新的进程和一个主线程。成功的话也将返回0值。


第二次修改之后,修改的是WaitForSingleObject(hMutexSuicide, INFINITE);,将INFINITE变为0执行这个程序。

由于整个程序要显示的是父子进程的通信,那么在父子进程的同步正式通过pv操作来完成的。

P操作:WaitForSingleObject(hMutexSuicide, INFINITE);

V操作:ReleaseMutex(hMutexSuicide)

通过互斥体的方式,利用互斥的机制来实现同步,此程序并没有明显的临界区,如果非要划分一个临界区的话,那么就应该是parent函数里面的getchar(),因为在没有修改之前,父进程必须执行完这个语句的时候,才会执行接下来的V操作,从而让子进程继续执行下去。

子进程的P操作函数,接受到了hMutexSuicide这个信号量的信息,得以获得互斥体,进入临界区,则继续执行子进程,最后关闭进程,执行CloseHandle(hMutexSuicide);语句。至此,父子进程的通讯和进程的结束伴随着3次修改都已经完成。




#include<windows.h>
#include<iostream>
#include<stdio.h>
#include<cstring>
using namespace std;

static LPCTSTR g_szMutexName = "w2kdg.ProcTerm.mutex.Suicide";

void StartClone()
{
	TCHAR szFilename[MAX_PATH];
	GetModuleFileName(NULL, szFilename, MAX_PATH);
	//返回	文件名,包括这个执行文件的路径,都同统一写入szFilename这个缓冲区里面,如果路径名或者文件名超过了MAX_PATH将会截断多出的部分
	TCHAR szCmdLine[MAX_PATH];
	wsprintf(szCmdLine, "\"%s\" child" , szFilename) ;
	//将szFilename 和 nCloneID 以规定的格式写入到szCmdLine中

	STARTUPINFO si;
	ZeroMemory(&si, sizeof(si));
	si.cb = sizeof(si);

	PROCESS_INFORMATION pi;   //这个结构体将存储CreateProcess返回的创建新的进程的一些信息以及他的主要线程
	BOOL bCreateOK = ::CreateProcess(
		szFilename,
		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
		);
	/*
	互斥体实现了“互相排斥”(mutual exclusion)同步的简单形式(所以名为互斥体(mutex))。
	互斥体禁止多个线程同时进入受保护的代码“临界区”(critical section)。
	因此,在任意时刻,只有一个线程被允许进入这样的代码保护区。任何线程在进入临界区之前,
	必须获取(acquire)与此区域相关联的互斥体的所有权。如果已有另一线程拥有了临界区的互斥体,
	其他线程就不能再进入其中。这些线程必须等待,直到当前的属主线程释放(release)该互斥体。
	*/
	if(hMutexSuicide != NULL)
	{
		cout << "creating the child process" << endl;
		StartClone();
		cout << "telling the child process to quit" << endl;
		getchar();
		ReleaseMutex(hMutexSuicide);
		/*
		一个线程释放了互斥对象的控制权后,如果其他进程在等待互斥对象置位,
		则等待的线程可以得到该互斥对象,等待函数返回,互斥对象被新的线程所拥有。
		并且会发送信号给waitforsingleobject
		*/
		CloseHandle(hMutexSuicide);
	}
}

void Child()
{
	HANDLE hMutexSuicide = OpenMutex(
		SYNCHRONIZE,
		FALSE,
		g_szMutexName
		);
	if(hMutexSuicide != NULL)
	{
		cout << "child waiting for suicide instructions" << endl;
		WaitForSingleObject(hMutexSuicide, INFINITE);
		/*
		WaitForSingleObject函数用来检测hMutexSuicide事件的信号状态,在某一线程中调用该函数时
		,线程暂时挂起,如果在挂起的dwMilliseconds毫秒内,
		线程所等待的对象变为有信号状态,则该函数立即返回;
		如果超时时间已经到达dwMilliseconds毫秒,但hMutexSuicide所指向的对象还没有变成有信号状态,函数照样返回。
		参数dwMilliseconds有两个具有特殊意义的值:0和INFINITE。若为0,则该函数立即返回;
		若为INFINITE,则线程一直被挂起,直到hHandle所指向的对象变为有信号状态时为止。
		*/
		cout << "Child quiting" << endl;
		getchar();
		CloseHandle(hMutexSuicide);
	}
}

int main(int argc, char* argv[])
{
	if(argc > 1 && strcmp(argv[1], "child") == 0)
	{
		Child();
	}
	else
	{
		Parent();
	}
	return 0;
}


你可能感兴趣的:(操作系统课程设计父子进程的简单通信以及终止进程源码解析)