冒着异常反模式的风险......进行一些修改
假设我有一个在某些机器上 24x7 运行的库。即使代码坚如磐石,硬件故障迟早也会触发异常。我希望针对此类事件采取某种故障保护措施。一种方法是编写封装每个 api a 的包装函数:
returnCode=DEFAULT;
try
{
returnCode=libraryAPI1();
}
catch(...)
{
returnCode=BAD;
}
return returnCode;
然后,库的调用者重新启动整个线程,如果 returnCode 错误,则重新初始化模块。
事情可能会变得非常糟糕。例如,
如果 try 块(或 libraryAPI1())具有:
func1();
char *x=malloc(1000);
func2();
如果 func2() 抛出异常,则 x 将永远不会被释放。同样,文件损坏也是一个可能的结果。
您能否告诉我在这种情况下还可能出现哪些其他问题?
Lets say that I have a library which runs 24x7 on certain machines. Even if the code is rock solid, a hardware fault can sooner or later trigger an exception. I would like to have some sort of failsafe in position for events like this. One approach would be to write wrapper functions that encapsulate each api a:
returnCode=DEFAULT;
try
{
returnCode=libraryAPI1();
}
catch(...)
{
returnCode=BAD;
}
return returnCode;
The caller of the library then restarts the whole thread, reinitializes the module if the returnCode is bad.
Things CAN go horribly wrong. E.g.
if the try block(or libraryAPI1()) had:
func1();
char *x=malloc(1000);
func2();
if func2() throws an exception, x will never be freed. On a similar vein, file corruption is a possible outcome.
Could you please tell me what other things can possibly go wrong in this scenario?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
硬件故障可能不会导致 C++ 异常。在某些系统上,硬件异常是与 C++ 异常完全不同的机制。在其他方面,C++ 异常构建在硬件异常机制之上。所以这实际上并不是一个一般的设计问题。
如果您希望能够恢复,则需要具有事务性——每个状态更改都需要运行完成或完全取消。 RAII 就是其中之一。正如克里斯·贝克在另一个答案中指出的那样,需要说明的不仅仅是资源获取。
有一种复制-修改-交换习惯用法在事务中被大量使用,但如果您尝试调整工作代码来处理这种百万分之一的情况,那么它可能太重了。
如果您确实需要鲁棒性,那么请将代码隔离到一个进程中。如果硬件故障终止了该进程,您可以让看门狗重新启动它。操作系统将回收丢失的资源。您的代码只需要担心持久状态的事务性,例如保存到文件中的内容。
A hardware failure may not lead to a C++ exception. On some systems, hardware exceptions are a completely different mechanism than C++ exceptions. On others, C++ exceptions are built on top of the hardware exception mechanism. So this isn't really a general design question.
If you want to be able to recover, you need to be transactional--each state change needs to run to completion or be backed out completely. RAII is one part of that. As Chris Becke points out in another answer, there's more to state than resource acquisition.
There's a copy-modify-swap idiom that's used a lot for transactions, but that might be way too heavy if you're trying to adapt working code to handle this one-in-a-million case.
If you truly need robustness, then isolate the code into a process. If a hardware fault kills the process, you can have a watchdog restart it. The OS will reclaim the lost resources. Your code would only need to worry about being transactional with persistent state, like stuff saved to files.
您可以控制libraryAPI 的实现吗?
如果它适合OO模型,则需要使用RAII模式来设计它,这保证了析构函数(将释放所获取的资源)在异常时被调用。
使用资源管理助手(例如智能指针)也有帮助
Do you have control over libraryAPI implementation ?
If it can fit into OO model, you need to design it using RAII pattern, which guarantees the destructor (who will release acquired resources) to be invoked on exception.
usage of resource-manage-helper such as smart pointer do help too
例外的问题是 - 即使您使用 RAiI 进行重新设计 - 它仍然很容易使代码变得不同步:
现在,该示例可能看起来很人为,但如果您用 stateA++ 和 stateB++ 代替操作以某种方式改变类的状态,此类的预期结果是状态保持同步。 RAII 可能会解决使用异常时与状态相关的一些问题,但它所做的只是提供一种错误的安全感 - 如果 SomeOtherMethod() 抛出异常,则需要分析所有周围的代码以确保后置条件 (stateA. delta == stateB.delta) 得到满足。
The problem with exeptions is - even if you do re-engineer with RAiI - its still easy to make code that becomes desynchronized:
Now, the example might look artifical, but if you substitue stateA++ and stateB++ for operations that change the state of the class in some way, the expected outcome of this class is for the states to remain in sync. RAII might solve some of the problems associated with state when using exceptions, but all it does is provide a false sense of security - If SomeOtherMethod() throws an exception ALL the surrounding code needs to be analyzed to ensure that the post conditions (stateA.delta == stateB.delta) are met.
此代码:
不是 C++ 代码。这就是人们所说的带有类的C。它是一种看起来像 C++ 的程序风格,但与现实生活中 C++ 的使用方式并不相符。原因是;良好的异常安全 C++ 代码实际上从不需要在代码中(直接)使用指针,因为指针始终包含在专门设计用于在异常安全庄园(通常是智能指针或容器)中管理其生命周期的类中。
该代码的 C++ 等效项是:
This code:
Is not C++ code. This is what people refer to as C with classes. It is a style of program that looks like C++ but does not match up to how C++ is used in real life. The reason is; good exception safe C++ code practically never requires the use of pointer (directly) in code as pointers are always contained inside a class specifically designed to manage their lifespan in an exception safe manor (Usually smart pointers or containers).
The C++ equivalent of that code is: