Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2275968
  • 博文数量: 668
  • 博客积分: 10016
  • 博客等级: 上将
  • 技术积分: 8588
  • 用 户 组: 普通用户
  • 注册时间: 2008-05-29 19:22
文章分类

全部博文(668)

文章存档

2011年(1)

2010年(2)

2009年(273)

2008年(392)

分类:

2008-08-07 09:01:10

大家现在知道,在中有完善的异常处理机制,同样在中也有很不错的异常处理机制来支持,另外在其它许多现代编程语言中,也都有各自的异常处理编程机制,如Ada语言等。那么为什么现在此处还在讨论,中所提供的异常处理机制呢?这是因为在许多系统中,编程语言所提供的异常处理机制的实现,都是建立在操作系统中所提供的异常处理机制之上,如平台上的VC编译器所实现的C++异常处理模型,它就是建立在SEH机制之上的,在“爱的秘密”篇中,探讨VC中异常处理模型实现的时候,会进行更深入的研究和分析。另外,当然也有其它的系统,如操作系统上的gcc就没有采用到操作系统中所提供的异常处理机制。但是这样会有一个很大的缺点,那就是对于应用程序的开发者而言,它不能够很好在自己的应用程序中,来有效控制操作系统中所出现的一些意外的系统异常,例如程序执行过程中可能出现的段错误,被0除等计算异常,以及其它许多不同类型的系统异常等。所以Linux操作系统上的gcc编译的程序中,它只能捕获程序中,曾经被自己显式地throw出来的异常,而对于系统异常,catch block是毫无办法的。

  因此,操作系统平台中所提供的异常处理机制是非常有必要的。而且,异常处理机制的实现也是操作系统设计时的一个重要课题。通常,类操作系统所提供的异常处理机制是大家非常熟悉的,那就是操作系统中的信号量处理(Signal Handling),好像这也应该是Posix所定义异常处理接口,因此Window系列操作系统平台也支持这种机制,“信号量处理”编程机制也会在后面的章节中进一步深入讨论。而现在(以及在接下来的几篇文章中),将全面阐述Window系列操作系统平台提供的另外一种更完善的异常处理机制,那就是大名鼎鼎的结构化异常处理(Structured Exception Handling,SEH)的编程方法。

  SEH设计的主要动机

  下面是出自《Window核心编程》中一小段内容的引用:

  “在Windows中引入SEH的主要动机是为了便于操作系统本身的开发。操作系统的开发人员使用SEH,使得系统更加强壮。我们也可以使用SEH,使我们的自己的程序更加强壮。使用SEH所造成的负担主要由编译程序来承担,而不是由操作系统承担。当异常块(exception block)出现时,编译程序要生成特殊的代码。编译程序必须产生一些表( t a b l e)来支持处理SEH的。编译程序还必须提供回调( c a l l b a c k)函数,操作系统可以调用这些函数,保证异常块被处理。编译程序还要负责准备栈结构和其他内部信息,供操作系统使用和参考。在编译程序中增加SEH支持不是一件容易的事。不同的编译程序厂商会以不同的方式实现SEH,这一点并不让人感到奇怪。幸亏我们可以不必考虑编译程序的实现细节,而只使用编译程序的SEH功能。”

  的确,SEH设计的主要动机就是为了便于操作系统本身的开发。为什么这么说呢?这是因为操作系统是一个非常庞大的系统,而且它还是处于计算机整个系统中,非常底层的系统软件,所以要求“操作系统”这个关键的系统软件必须要非常强壮,可靠性非常高。当然提升操作系统软件的可靠性有许多有效的方法,例如严谨的设计,全面而科学的测试。但是俗话说得好,“智者千虑,必有一失”。因此在编程代码中,有一个非常有效的异常处理机制,将大大提高软件系统的可靠性。说道这里,也许很多朋友们说:“阿愚呀!你有没有搞错,无论是C++还是C语言中,不都有很好的异常处理机制吗?为什么还需要另外再设计一种呢?”。的确没错,但是请注意,操作系统由于效率的考虑,它往往不会考虑采用C++语言来编写,它大部分模块都是采用C语言来编码的,另外还包括一小部分的汇编代码。所以,这样操作系统中最多只能用goto语句,以及setjmp和longjmp等机制。但Window的设计者认为这远远不够他们的需要,离他们的要求相差甚远。而且,尤其是在操作系统中,最大的软件模块就是设备的驱动程序了,而且设备的驱动程序模块中,其中的又有绝大部分是由第3方(硬件提供商)来开发的。这些第3方开发的驱动程序模块,与操作系统核心关联紧密,它将严重影响到整个操作系统的可靠性和稳定性。所以,如何来促使第3方开发的驱动程序模块变得更加可靠呢?它至少不会影响到操作系统内核的正常工作,或者说甚至导致操作系统内核的崩溃。客观地说,这的确很难做得到,因为自己的命运掌握在别人手里了。但是Window的设计者想出了一个很不错的方法,那就是为第3方的驱动人员提供SEH机制,来最大程度上提升第3方开发出的驱动程序的可靠性和稳定性。相信有过在Windows平台上开发过驱动程序的朋友们对这一点深有感触,而且有关驱动程序开发的大多数书籍中,都强烈建议你在编程中使用SEH机制。

  现在来谈谈为什么说,C语言中的setjmp和longjmp机制没有SEH机制好呢?呵呵!当然在不深入了解SEH机制之前,来讨论并很好地解释清楚这个问题也许是比较困难的。但是主人公阿愚却认为,这里讨论这个问题是最恰当不过的了。因为这样可以很好地沿着当年的SEH的设计者们的足迹,来透析他们的设计思想。至少我们现在可以充分地分析setjmp和longjmp机制的不足之处。例如说,在实际的编程中(尤其是系统方面的编程),是不是经常遇到这种状况,示例代码如下:

  #include

  #include

  #include

  jmp_buf mark;

  void test1()

  {

  char* p1, *p2, *p3, *p4;

  p1 = malloc(10);

  if (!p1) longjmp(mark, 1);

  p2 = malloc(10);

  if (!p2)

  {

  // 这里虽然可以释放,

  // 但是很容易忘记,也容易出错

  free(p1);

  longjmp(mark, 1);

  }

  p3 = malloc(10);

  if (!p3)

  {

  // 这里虽然可以释放资源

  // 但是程序员很容易忘记,也容易出错

  free(p1);

  free(p2);

  longjmp(mark, 1);

  }

  p4 = malloc(10);

  if (!p4)

  {

  // 这里虽然可以释放资源

  // 但是程序员很容易忘记,也容易出错

  free(p1);

  free(p2);

  free(p3);

  longjmp(mark, 1);

  }

  // do other job

  free(p1);

  free(p2);

  free(p3);

  free(p4);

  }

  void test()

  {

  char* p;

  p = malloc(10);

  // do other job

  test1();

  // do other job

  // 这里的资源可能得不到释放

  free(p);

  }

  void main( void )

  {

  int jmpret;

  jmpret = setjmp( mark );

  if( jmpret == 0 )

  {

  char* p;

  p = malloc(10);

  // do other job

  test1();

  // do other job

  // 这里的资源可能得不到释放

  free(p);

  }

  else

  {

  printf("捕获到一个异常\n");

  }

  }

  上面的程序很容易导致内存资源泄漏,而且程序的代码看上去也比较别扭。程序员编写代码时,总要非常地小心翼翼地释放相关的资源。有可能一个稍微的处理不当,就可能导致资源泄漏,甚至更严重的是引发系统的死锁,因为在编写驱动程序时,毕竟与一般的应用程序有很大的不同,会经常使用到进程间的一些同步和互斥控制等。

  怎么办?如果有一种机制,在程序中出现异常时,能够给程序员一个恰当的机会,来释放这些系统资源,那该多好呀!其实这种需求有点相当于C++中的析构函数,因为它不管何种情况下,只要对象离开它生存的作用域时,它总会被得以执行。但是在C语言中的setjmp和longjmp机制,却显然做不到这一点。SEH的设计者们考虑到了这一点,因此在SEH机制中,它提供了此项功能给程序开发人员。这其实也是SEH中最强大,也最有特色的地方。另外,SEH还提供了程序出现异常后,有效地被得以恢复,程序继续执行的机制,这也是其它异常处理模型没有的(虽然一般情况下,没有必要这样做;但是对于系统模块,有时这是非常有必要的)。

  SEH究竟何物?

  首先还是引用MSDN中关于SEH的有关论述,如下:

  Windows 95 and Windows NT support a robust approach to handling exceptions, called structured exception handling, which involves cooperation of the operating system but also has direct support in the programming language.

  An “exception” is an event that is unexpected or disrupts the ability of the process to proceed normally. Exceptions can be detected by both hardware and software. Hardware exceptions include dividing by zero and overflow of a numeric type. Software exceptions include those you detect and signal to the system by calling the RaiseException function, and special situations detected by Windows 95 and Windows NT.

  You can write more reliable code with structured exception handling. You can ensure that resources, such as memory blocks and files, are properly closed in the event of unexpected termination. You can also handle specific problems, such as insufficient memory, with concise, structured code that doesn’t rely on goto statements or elaborate testing of return codes.

  Note These articles describe structured exception handling for the C programming language. Although structured exception handling can also be used with C++, the new C++ exception handling method should be used for C++ programs. See Using Structured Exception Handling with C++ for information on special considerations.

  我们虽然都知道,SEH是Window系列操作系统平台提供的一种非常完善的异常处理机制。但这毕竟有些过于抽象了点,对于程序员而言,它应该有一套类似于像C++中那样的try,catch,throw等几个关键字组成的完整的异常处理模型。是的,这的确没错,SEH也有类似的语法,那就是它由如下几个关键字组成:

  __try

  __except

  __finally

  __leave

  呵呵!这是不是很多在Windows平台上做开发的程序员朋友们都用过。很熟悉吧!但是这里其实有一个认识上的误区,大多数程序员,包括很多计算机书籍中,都把SEH机制与__try,__except,__finally,__leave异常模型等同起来。这种提法是不对的,至少是不准确的。因为SHE狭义上讲,只能算是Window系列操作系统所提供的一种异常处理机制;而无论是__try,__except,__finally,__leave异常模型,还是try,catch,throw异常模型,它们都是VC所实现并提供给开发者的。其中__try,__except,__finally,__leave异常模型主要是提供给C程序员使用;而try,catch,throw异常模型,它则是提供给C++程序员使用,而且它也遵循C++标准中异常模型的定义。这多种异常机制之间的关系如下图所示:

  

  总结

  为了更进一步认识SEH机制,认识SEH与__try,__except,__finally,__leave异常模型机制的区别。下一篇文章中,主人公阿愚还是拿出一个具体的例子程序来与大家一起分享。注意,它那个例子中,它既没有使用到__try,__except,__finally,__leave异常模型;也没有利用到try,catch,throw异常模型。它直接使用到Windows操作系统所提供的SEH机制,并完成一个简单的封装。继续吧!GO!

阅读(1010) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~