Windows核心编程学习笔记-------23章

23章终止处理程序

一、SHE(结构化异常处理)好处

二、SHE是什么

三、SHE怎么用

四、SHE工作原理

一、先了解SHE的好处:可让我们在写代码时,先集中精力完成软件的正常工作流程。若在运行时出现什么问题,系统会捕获这个问题,并通知我们。使用SHE并不意味着可完全忽略代码中可能出现的错误,但可将软件注意功能编写和软件异常情况处理这两个任务分开。

二、SHE包括两方面的功能:终止处理和异常处理。本章讨论终止处理,下章讨论异常处理。区分SHEC++异常处理:C++异常处理在形式上表现为使用关键字catch和throw,这个结构化异常处理的形式不同。Microsoft Visual C++支持异常处理,它再内部实现上其实就是利用了编译器和Windows操作系统的结构化异常处理功能。

三、终止处理程序确保不管一个代码块(被保护代码(gaurded body))是如何退出的,另一个代码块(终止处理程序(termination handler))总能被调用和执行。终止处理的语法如下(当使用Microsoft Visual C++编译器时):

_try

{//gaurded body}

_finally

{//termination handler}//除非调用ExitProcessExitThreadTerminateProcessTerminatedThread来终止进程或线程,否则_finally代码块都能执行。

实例讲解:

1、Funcenstein2函数:

DWORD Funcensterin2()
{
	DWORD dwTemp;
	//1.do any processing here
	_try
	{
		//2.request permission to access protected data, and then use it.
		WaitForSingleObject(g_hSem, INFINITE);

		g_dwProcetedData = 5;
		dwTemp = g_dwProcetedData;

		//return the new value;
		return(dwTemp);
	}
	_finally
	{
		//3.allow others to use protected data.
		ReleaseSemphore(g_hSem, 1, NULL);
	}

	//continue processing--this code will never execute in this version.
	dwTemp = 9;
	return(dwTemp);
}

         通过使用终止处理程序可防止过早的执行return语句。当try块中有return语句时,试图退出try块时,编译器会让finally代码块在它之前执行。此函数可保证在函数退出前释放信号量。

         原理:编译器检查程序代码时,当发现try块中有return语句,就会生成一些代码先将返回值保存在它创建的临时变量里,然后再执行finally块,此过程称之为局部展开。即当系统因try代码块中代码提取退出而执行finally代码块时,就会发生局部展开。

         缺点:为使此机制运行,编译器必须生成一些额外代码,而系统也必须执行一些额外工作,所有应避免在try块中使用让其提前退出的语句,如return、continue、break、goto等。

2、Funcfurter1函数:

DWORD Funcfurter1()
{
	DWORD dwTemp;
	//1.do any processing here.
	_try
	{
		//2.request permission to access protected data, and then use it.
		WaitForSingleObject(g_hSem, INFINITE);
		dwTemp = Funcinator(g_dwProtectedData);
	}
	_finally
	{
		//3.allow others to use protected data.
		ReleaseSemaphore(g_hSem, 1, NULL);
	}

	//4.continue processing.
	return(dwTemp);
}

         若代码块中Funcinator函数存在一个缺陷会导致程序访问非法内存。若无SHE,这种情况最终导致Windows错误报告(Windows Error Reporting,简称WER)。这样进程就会终止(因非法内存访问),但信号量将依然被占用并再也得不到释放。其他进程中线程就会因无休止等待这个信号量而得不到CPU时间片。若将释放信号量的语句置于finally块中,即使try块中调用的函数发生了内存访问违规这样的异常,这个信号量仍可被释放。

但自Windows Vista开始,须显示包含try/finally框架,以确保在异常跑出时,finally代码块会执行。早起的windows系统里,异常发生时,finally块也不能保证绝对得到执行。如在XP里,若一个”栈耗尽异常”发生在try代码块里,finally块很可能得不到机会执行。

调用ExitThread或ExitProcess可立即终止线程或进程,而不会引发finally代码块执行。同样,若当前线程或进程因另一个程序调用TerminateThread或TerminateProcess而不得不结束,finally代码块也不会被执行。有些C运行期函数(如abort)因其内部调用ExitProcess,也会导致finally块不能执行。

3、Funcarama3函数:

DWORD Funcarama3()
{
	//IMPORTANT:initialize all variables to assume failure.
	HANDLE hFile = INVALID_HANDLE_VALUE;
	PVOID pvBuf = NULL;

	_try
	{
		DWORD dwNumBytesRead;
		BOOL bOk;

		hFile = CreateFile(_T("SOMEDATA.DATA"), GENERIC_READ,
			FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
		if (INVALID_HANDLE_VALUE == hFile)
		{
			return false;
		}

		pvBuf = VirtualAlloc(NULL, 1024, MEM_COMMIT, PAGE_EADWRITE);
		if(NULL == pvBuf)
		{
			return false;
		}

		bOk = ReadFile(hFile, pvBuf, 1024, &dwNumBytesRead, NULL);
		if (!bOk || (dwNumBytesRead != 1024))
		{
			return false;
		}
		//do some calculation on the data.
	}
	_finally
	{
		//clean up all the resources.
		if (pvBuf != NULL)
			ViutualFree(pvBuf, MEM_RELEASE | MEM_DECOMMIT);
		if (hFile != INVALID_HANDLE_VALUE)
			CloseHandle(hFile);
	}
	//continue processing
	return true;
}

精髓在于所有的清理工作都被放在并且只放在一个地方:finally块。否则,每个判断出错中都要处理这些清理工作。

4、Funcarama4终结版:

DWORD Funcarama4()
{
	//IMPORTANT:initialize all variables to assume failure.
	HANDLE hFile = INVALID_HANDLE_VALUE;
	PVOID pvBuf = NULL;

	//注意函数不能成功执行
	BOOL bFunctionOK = FALSE;

	_try
	{
		DWORD dwNumBytesRead;
		BOOL bOk;

		hFile = CreateFile(_T("SOMEDATA.DATA"), GENERIC_READ,
			FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
		if (INVALID_HANDLE_VALUE == hFile)
		{
			_leave;
		}

		pvBuf = VirtualAlloc(NULL, 1024, MEM_COMMIT, PAGE_EADWRITE);
		if(NULL == pvBuf)
		{
			_leave;
		}

		bOk = ReadFile(hFile, pvBuf, 1024, &dwNumBytesRead, NULL);
		if (!bOk || (dwNumBytesRead != 1024))
		{
			_leave;
		}
		//do some calculation on the data.
		//表明整个函数执行成功
		bFunctionOK = TRUE;
	}
	_finally
	{
		//clean up all the resources.
		if (pvBuf != NULL)
			ViutualFree(pvBuf, MEM_RELEASE | MEM_DECOMMIT);
		if (hFile != INVALID_HANDLE_VALUE)
			CloseHandle(hFile);
	}
	//continue processing
	return bFunctionOK;	
}

         关键字_leave会导致代码执行块跳转到try块的结尾(即闭花括号处)因这种情况,代码执行将正常从try进入finally,所以不会产生额外开销。

         此种方式在函数里使用终止处理程序时,最好在进入try块之前,将所有资源句柄都初始化为无效值。这样可在finally块里检查哪些资源得到了成功分配,从而得知哪些资源需要释放。另一个检查哪些资源需要释放的常见做法是,为成功分配的资源设置标志,然后在finally块里检查这些标志以决定资源是否需要释放。

四、上面的实例讲的差不多了,补充两点:1.引起finally块执行的情形。

1)从try块到finally的正常代码控制流。

2)局部展开:从try块中的提前退出(return、break、continue、got、longjump等引起)将程序控制流强制转入finally块。

3)全局展开。

         2.使用终止处理的程序的好处:

Ø  清理工作集中在一个地方执行,且保证能得到执行,从而简化了错误处理。

Ø  提供代码的可读性。

Ø  让代码更容易维护。

Ø  若正确使用,对程序性能和体积的影响是微小的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值