第二十三章 终止处理程序
本章内容
通过实例理解终止处理程序
VC++支持SEH(Structured exception handling)来使得开发代码过程能够把代码和错误处理的逻辑分离开来。
SEH是编译器在编译代码过程中加入了特殊的处理代码,生成SEH的数据结构和操作系统相关的代码。参考深入解析Win32结构化异常
SEH实际上包含两方面的功能:终止处理(termination handling)和异常处理(exception handling)
终止处理确保不管一个代码块(被保护的代码块)是如何退出的,另一个代码块(终止处理程序)总能被调用和执行。终止处理的语法如下:
__try{
// Guard body
// ...
}
__finally{
// Termination handler
// ...
}
编译器和操作系统协同工作保障了无论被保护的代码是如何退出的(return, goto, longjump, 除非调用了ExitProcess , ExitThread, TerminateProcess, TerminateThread来终止进程或线程) ,终止处理程序都会表调用(__finally语句块中的代码)
通过实例理解终止处理程序
1. Funcenstein1函数
DWORD Funcenstein1() {
DWORD dwTemp;
// 1. Do any processing here.
__try{
// 2. Request permission to access
// protected data, and then use it.
WaitForSingleObject(g_hSem, INFINITE);
g_dwProtectedData = 5;
dwTemp = g_dwProtectedData;
}
__finally{
// 3. Allow other to use protected data.
ReleaseSemaphore(g_hSem, 1, NULL);
}
// 4. continue processing
return dwTemp;
}
2. Funcenstein2函数
DWORD Funcenstein2() {
DWORD dwTemp;
// 1. Do any processing here.
__try{
// 2. Request permission to access
// protected data, and then use it.
WaitForSingleObject(g_hSem, INFINITE);
g_dwProtectedData = 5;
dwTemp = g_dwProtectedData;
// return the new value.
return dwTemp;
}
__finally{
// 3. Allow other to use protected data.
ReleaseSemaphore(g_hSem, 1, NULL);
}
// 4. continue processing
// will never execute in this version
dwTemp = 9;
return dwTemp;
}
通过__finally保证了信号量被即使释放。
在__try语句块中返回return的时候,由于存在__finally语句块,会强制执行__finally块中的代码然后再return
编译器在编译__try语句块中发现存在一个return语句(类似ret指令),编译器会先将返回值保存在一个临时变量中(通常是push xxx)。然后再调转到finally代码块(这个过程称为局部展开)一旦finally代码块执行完毕,编译器所创建的临时变量的值就会返回给函数调用者。
可以看到ret语句被编译成了一系列语句,最后通过一系列跳转到了_finally语句块内并执行其中的代码。
同时__finally语句块执行以后最后有一条ret指令最终会返回所有调用然后让函数返回。
注意在try语句块中使用return语句会生成大量了代码,多次跳转才能回到finally语句块,这会损失性能。应该改用__leave
另外异常处理通常用来捕获哪些本来不应该发生的异常。如果是常见问题,应该显示地检查这些问题以提供运行效率(例如空指针访问,除0错误等)
通常让__try语句正常执行以后进入__finally这