10.5.3 什么是逻辑容错(1)
您可以使用C++(www.cppentry.com)异常处理工具和异常类来加强PADL和PBS的语义。通过继承扩展异常类和错误类,有助于测试过程捕捉应用程序PBS的C++(www.cppentry.com)谓词实现中不合逻辑的情况。我们将这个过程称作对应用程序加入逻辑容错。
C++(www.cppentry.com)异常处理工具的基础如何被使用对软件的架构至少有两个重要的影响:
软件架构中的控制流会被throw机制改变。
使用的异常类引入新的类型,而且每种类型有其自身的语义。
从问题域到知道如何将系统带领到一致状态的其他区域的控制转移,以及了解异常抛出的语义,使得您可以开始研究逻辑容错的目的。异常抛出的语义描述了异常条件是什么以及建议应当做些什么。控制的转移将您带到实现异常策略的代码。异常策略被设计为使得软件对缺陷和系统失效具有弹性。在C++(www.cppentry.com)中,catch( )机制既可以直接实现异常策略,也可以创建对象并调用实现异常策略的函数:
- catch(some_exception){
-
- //Execute exceptions strategy
-
- }
1. 异常处理程序
catch{}块被称作异常处理程序。C++(www.cppentry.com)程序可包含多个异常处理程序。每个异常处理程序同一种或多种类型关联(取决于异常的类层次结构)。异常处理程序的3个基本功能是:
登记它可以处理的异常类型
对发生了什么异常进行记录或以某种方式记入日志(有时这需要通知)
执行适当的异常处理策略
异常处理策略有许多种。终止模型(termination model)中的异常处理策略的主要目的是将软件带回到一致的状态,从而使软件可以继续在某个可接受的级别下运行。表10-6包含了常用的异常策略。
表10-6
|
异 常 策 略< xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /> |
描 述 |
|
资源再分配和回收 |
试图:
● 再分配内存
● 关闭文件
● 释放互斥量
● 关闭信号量
● 释放内存
● 查找文件
● 关闭进程
● 改变引发问题的进程的安全性 |
|
事务或数据回滚 |
撤销未完成事务的步骤,将数据
回滚到数据有效的某个检查点 |
|
操作重试 |
重试一次操作:
● 使用最初的资源
● 使用改变后的资源
● 在一段时间间隔之后
● 在附加条件被满足之后 |
|
冗余和故障恢复 |
将处理移交给其他线程或与当前
进程并行运行的进程 |
|
通知外部援助 |
请求从其他软件agent、拟人化
用户或其他系统获得援助 |
使用哪种异常处理策略将对软件架构产生很大的影响。这就意味着必须在软件设计阶段就将异常处理策略包括进来。在接近并行编程(www.cppentry.com)的声明式解释中,您正在向着逻辑模型移动。最终,您希望将不合逻辑的模型或不合理的程序行为视作异常。因此,异常处理策略从PADL的第5层和PBS中产生。它是软件架构的基本部分。如果总体软件架构是脆弱的,那么异常处理策略注定会失败。
异常抛出的语义与实现的异常策略紧密相关。在软件架构的上下文中理解异常的语义同决定在异常处理过程中将控制转移到哪里同样重要。C++(www.cppentry.com)标准定义了多个有着自身语义的内置异常类。图10-1给出了C++(www.cppentry.com)异常类的类关系图。
这些异常类可通过继承得到扩展。C++(www.cppentry.com)也支持用户定义的异常类。
标准C++(www.cppentry.com)类库有9种异常类,被分成两组:运行时错误组和逻辑错误组。运行时错误组代表了难以预防的错误,而逻辑错误组代表了理论上可以避免的错误。
|
| (点击查看大图)图10-1 |
runtime_error类
runtime_error类系列是从exception类派生来的。3个类从runtime_error类派生得到:range_error、overflow_error和underflow_error。runtime_error类报告内部的计算或算术错误。runtime_error类从异常类祖先继承得到主要的功能。what( )方法、赋值运算符operator=( )和异常处理类的构造函数为runtime_error类提供了能力。runtime_error类提供了一个异常框架和架构蓝图。
logic_error类
logic_error类系列是从exception类派生来的。实际上,logic_error类系列的大部分功能也是从exception类继承来的。exception类包含了what( )方法,用来报告给用户所抛出的错误的描述。每个logic_error类系列中的类包含一个构造函数,用来裁剪针对该类的消息。
与runtime_error类类似,这些类是被设计为专用的。除非用户为这些类增加一些功能,否则它们只报告错误及其类型,其他什么都不能做。因此,9个通用异常类没有提供纠正动作或错误处理。看一下基本异常类在没有专门化时是如何工作的。示例10-1显示了如何抛出一个exception对象和logic_error对象。
示例10-1
- // Example 10-1 Throwing an exception object and a logic_error object.
-
- try{
- exception X;
- throw(X);
- }
-
- catch(const exception &X)
- {
- cout << X.what() << endl;
- }
-
- try{
- logic_error Logic("Logic Mistake");
- throw(Logic);
- }
-
- catch(const exception &X)
- {
- cout << X.what() << endl;
- }
基本的异常类只有构造、析构、赋值、复制和简单的报告功能。它们不包含纠正已经发生的故障的能力。异常类的what( )方法返回的错误消息将由传递给logic_error对象的构造函数的字符串确定。在示例10-1中,传递给构造函数的Logic Mistake字符串是由catch block( )中的what( )返回的。
派生新的异常类
异常类可以照原样的方式来使用,也就是它们仅用来报告描述已经发生的错误的错误消息。然而,这对于异常处理技术而言本质上是无用的。仅知道异常是什么并不能增加软件的可靠性。异常类层次结构的真正价值在于它为设计人员和开发人员提供的结构上的线路图。异常类提供了开发人员可以进行特化的基本错误类型。在运行时环境中发生的很多异常既可放置到logic_error类系列中,也可以放置到runtime_error类系列中。为了了解如何特化exception类,您可以将runtime_error作为一个例子。如前所述,runtime_error类是exception类的后代。可通过继承来特化runtime_error类。例如:
- class concurrent_ file_access_exception : public runtime_error{
- protected:
- //...
- int ErrorNumber;
- string DetailedExplanation;
- string FileName;
- //...
- public:
- virtual int takeCorrectiveAction(void)
- string detailedExplanation(void);
- //...
- };