系列文章目录
[笔记]Windows核心编程《一》错误处理、字符编码
[笔记]Windows核心编程《二》内核对象
[笔记]Windows核心编程《三》进程
[笔记]Windows核心编程《四》作业
[笔记]快乐的LInux命令行《五》什么是shell
[笔记]Windows核心编程《五》线程基础
[笔记]Windows核心编程《六》线程调度、优先级和关联性
[笔记]Windows核心编程《七》用户模式下的线程同步
[笔记]Windows核心编程《八》用内核对象进行线程同步
[笔记]Windows核心编程《九》同步设备I/O和异步设备I/O
[笔记]Windows核心编程《十一》Windows线程池
[笔记]Windows核心编程《十二》纤程
[笔记]Windows核心编程《十三》windows内存体系结构
[笔记]Windows核心编程《十四》探索虚拟内存
[笔记]Windows核心编程《十五》在应用程序中使用虚拟内存
[笔记]Windows核心编程《十六》线程栈
[笔记]Windows核心编程《十七》内存映射文件
[笔记]Windows核心编程《十八》堆栈
[笔记]Windows核心编程《十九》DLL基础
[笔记]Windows核心编程《二十》DLL的高级操作技术
[笔记]Windows核心编程《二十一》线程本地存储器TLS
[笔记]Windows核心编程《二十二》注入DLL和拦截API
[笔记]Windows核心编程《二十三》结构化异常处理
文章目录
系列文章目录
前言
C++异常处理的情况
情况1 释放信标情况
情况2 释放信标 try中加入return
情况3 释放信标 在try内使用Goto
情况4 释放信标 try调用函数抛异常
情况5 循环中使用try-finally
总结
1.SEH(Structured Exception Handling)和SJLJ(SetJump LongJump)区别对比
SEH:
2.SEH和c++异常处理区别?
3.C++异常处理的特点?
4. 编译程序是如何保证在try块可以退出之前执行finally块的?
前言
结构化异常处理,SEH(Structured Exception Handling)
SEH的好处:
就是当你编写程序时,只需要关注程序要完成的任务。如果在运行时发生什么错误,系统会发现并将发生的问题通知你。
使用 S E H所造成的负担主要由编译程序来承担,而不是由操作系统承担。当异常块(exception block)出现时,编译程序要生成特殊的代码。编译程序必须产生一些表( t a b l e)来支持处理S E H的数据结构。编译程序还必须提供回调( c a l l b a c k)函数,操作系统可以调用这些函数,保证异常块被处理。编译程序还要负责准备栈结构和其他内部信息,供操作系统使用
和参考。
SEH 包含两个主要功能:
结束处理
异常处理
SEH和c++异常处理区别:
不要将结构化异常处理同 C + +的异常处理相混淆。C + +异常处理是一种不同形式的异常处理,其形式是使用C + +关键字catch和throw。微软的Visual C++也支持C + +的异常处理,并且在内部实现上利用了已经引入到编译程序和 Windows操作系统的结构化异常处理的功能。
一个结束处理程序能够确保去调用和执行一个代码块(结束处理程序,termination handler),
而不管另外一段代码(保护体, guarded body)是如何退出的。结束处理程序的文法结构(使用微软的Visual C++编译程序)如下:
__try { //Guard body ... } __finally { // Terminal Handler ... }
__try和__finally关键字用来标出结束处理程序两段代码的轮廓。在上面的代码段中,操作系统和编译程序共同来确保结束处理程序中的__finally 代码块能够被执行,不管保护体(try块)是如何退出的。不论你在保护体中使用 return,还是goto,或者是longjump,结束处理程序(finally块)都将被调用。
总之,c++异常处理顺序是:
1.try 2.finally 3. try里的return或者finally之后的代码
C++异常处理的情况
情况1 释放信标情况
代码要等待信标( semaphore),改变保护数据的内容,保存局部变量dwTemp的新值,释放信标,将新值返回给调用程序。
DwORD Funcenstein1( ) { DWORD dwTemp; //1. Do any processing here. __try { //2. Request permission to access //protected data. and then use it.waitForSing1e0bject(g_hSem,INFINITE);g_dwProtectedData = 5; dwTemp = g_dwProtectedData ; } __fina1ly { //3.A1low others to use protected data.Re1easeSemaphore( g_hSem,1,NULL); } //4. Continue processing. return(dwTemp); }
最后的释放信标放在finally 是一定会执行的。
情况2 释放信标 try中加入return
DwORD dwTemp; // 1. Do any processing here.: __try { // 2. Request permission to access // protected data, and then 'use it. waitForSing1e0bject(g_hSem,INFINITE); g_dwProtectedData = 5; dwTemp = g_dwProtectedData ; //Return the new value. return(dwTemp) ; } __fina1ly { //3.Al1ow others to use protected data.Re1easeSemaphore( g_hSem,1,NULL); } // Continue processing--this code // wi11 never execute in this version.dwTemp = 9; return(dwTemp ); }
结果是,返回5。因为当提前return时,finally会先执行,然后再执行try内的return。
当return语句试图退出try块时,编译程序要确保finally块中的代码首先被执行。要保证finally块中的代码在try块中的return语句退出之前执行。Funcens tein2中,将对ReleaseSemaphore的调用放在结束处理程序块中,保证信标总会被释放。这样就不会造成一个线程一直占有信标,否则将意味着所有其他等待信标的线程永远不会被分配CP U时间。
编译程序是如何保证在try块可以退出之前执行finally块的?
查看总结4
情况3 释放信标 在try内使用Goto
DwORD Funcenstein3( ) { DwORD dwTemp; //1. Do any processing here. __try { //2. Request permission to access //protected data, and then use it. WaitForSingle0bject( g_hSem,INFINITE);g_dwProtectedData = 5; dwTemp = gdwProtectedData; //Try to jump over the fina11y b1ock. goto ReturnValue; } __fina11y { //3.Al1ow others to use protected data. Re1easeSemaphore( g_hSem,1.NULL); } dwTemp = 9; //4. Continue processing.Returnvalue: return(dwTemp); }
结果是:goto不会执行。会先try到goto时先finally在到retunrn(dwTemp)。
当编译程序看到try块中的goto语句,它首先生成一个局部展开来执行
finally 块中的内容。这一次,在 finally 块中的代码执行之后,在 ReturnValue 标号之后的代码将执行,因为在try块和finally块中都没有返回发生。这里的代码使函数返回 5。而且,由于中断了从try块到finally块的自然流程,可能要蒙受很大的性能损失(取决于运行程序的CPU)。
情况4 释放信标 try调用函数抛异常
try块中的Funcinator函数调用包含一个错误,会引起一个无效内存访问。
DMORD Funcfurter1(){ DWORD dwTemp; //1. Do any processing here. __try{ //2. Request permission to access //protected data. and then use it. WaitForSing1e0bject( g_hSem,INFINITE); dwTemp = Funcinator( g_dwProtectedData) ; } __final1y { //3.A11ow others to use protected data. ReleaseSemaphore( g .hSem,1,NULL); ) //4. Continue processing. return( dwTemp); )
结果是,正常释放信标,进程不会提前结束,导致信标没释放。不然就可能引起其他进程等待。
如果结束处理程序足够强,能够捕捉由于无效内存访问而结束的进程,我们就可以相信它也能够捕捉setjump和longjump的结合,还有那些简单语句如break和continue。
情况5 循环中使用try-finally
如下代码执行结果如何?
DWORD FuncaDoodleDoo( ) { DWORD dwTemp = 0; while (dwTemp < 10){ __try { if ( dwTemp == 2) continue; if ( dwTemp == 3 ) break; } __fina11y { dwTemp+t; } dwTemp++; } dwTemp += 10; return(dwTemp); }
总结
1.SEH(Structured Exception Handling)和SJLJ(SetJump LongJump)区别对比
SEH:
2.SEH和c++异常处理区别?
SEH和c++异常处理区别:
不要将结构化异常处理同 C + +的异常处理相混淆。C + +异常处理是一种不同形式的异常处理,其形式是使用C + +关键字catch和throw。微软的Visual C++也支持C + +的异常处理,并且在内部实现上利用了已经引入到编译程序和 Windows操作系统的结构化异常处理的功能。
3.C++异常处理的特点?
- 通过使用结束处理程序,可以避免 return语句的过早执行。
例如:try内return时 finally可以避免提前返回而没有释放。
注意除了以下几种情况不能处理:
当调用ExitThread或ExitProcess时,将立即结束线程或进程,而不会执行 finally块中的任何代码。
另外,如果由于某个程序调用 TerminalThread或 TerminalProcess,线程或进程将死掉,finally 块中的代码也不执行。
某些 C运行期函数(例如abort)要调用ExitProcess,也使finally块中的代码不能执行。
4. 编译程序是如何保证在try块可以退出之前执行finally块的?
当编译程序检查源代码时,它看到在try块中有return语句。这样,编译程序就生成代码将返回值 保存在一个编译程序建立的临时变量中。编译程序然后再生成代码来执行finally块中包含的指令,这称为局部展开。更特殊的情况是,由于try块中存在过早退出的代码,从而产生局部展开,导致系统执行finall y块中的内容。在finally块中的指令执行之后,编译程序临时变量的值被取出并从函数中返回。
故在编写代码时,就应该避免引起结束处理程序的t r y块中的过早退出,因为程序的性能会受到影响。