« 上一篇

复制和重新抛出异常

整个异常机制在C++中工作得很好,当然这仅限于单线程的情况。每个线程都可以抛出自己的异常,但它们必须在自己的线程内捕捉异常。一个线程中抛出的异常不能在另一个线程中捕获。当希望将异常处理机制和多线程编程结合在一起时,这会引入一些问题。

不使用标准线程库,就很难在线程间正常地处理异常,甚至根本办不到。标准线程库通过以下和异常相关的函数解决了这个问题。这些函数不仅可用于std:exception,还可以用于所有类型的异常:int、string、自定义异常等。

此删除在catch块中调用,返回一个exception ptr对象,这个对象引用目前正在处理的异常或其副本,如果没有处理异常,则返回空的exception ptr对象。只要存在引用它的exception ptr类型的对象,那么引用的异常对象还是可用的。Exception ptr的类型是NullablePointer,这意味着这个变量很容易通过简单的if语句来检查。

这个函数重新抛出由exception ptr参数引用的异常。重新排除异常不要求在最开始产生这个引用的异常的那个线程中,因此这个特别特别适合于跨不同线程的异常处理。

这个函数创建一个引用给定异常对象副本的exception ptr对象。下面的threadFuncO函数将上述函数包装在一个try/catch块中,捕捉doSomeWorkO可能抛出的所有异常。为threadFuncO传入了一个参数,其类型为exception ptr。一旦捕获一个异常,就通过current exceptionO函数获得正在处理异常的引用,然后将这个引用赋给exception ptr参数。

以下的doWorkInThread函数在主线程中调用。其职责是创建一个新的线程,并开始在这个线程中执行threadFuncO函数。对类型为exception ptr的对象的引用作为参数传入threadFuncO。一旦创建了线程,doWorkInThread函数就使用joinO方法等待线程执行完毕,之后检查error对象。由于exception ptr的类型为NullablePointer,所以很容易通过if语句进行检查。如果它是一个非空值,则在当前线程中重新抛出这个异常,在这个例子中的当前线程即主线程。在主线程中重新抛出异常,异常就从一个线程转移到另一个线程。

为让这个例子紧凑且更容易理解,doWorkInThreadO函数通过joinO组织并等待线程完成。当然,在实际应用程序中,不应该阻塞主线程。例如,在GUI应用程序中,可以让threadFuncO函数给UI线程发送一个消息,消息的参数为current exceptionO结果的一份副本。