中毒
尽管所有不安全的代码必须确保其具有最小的异常安全性,但并非所有类型都能确保最大的异常安全性。即使类型本身能做到,你的代码也可能会赋予它额外的含义。例如,整数当然是异常安全的,但它本身没有任何语义。可能会发生这样的情况:发生 panic 的代码未能正确更新整数,从而产生不一致的程序状态。
这通常是没问题的,因为任何目睹异常的事物都将要被销毁。例如,如果你将一个 Vec 发送到另一个线程,而该线程发生 panic,那么 Vec 是否处于奇怪的状态并不重要。它将被 drop 并永远消失。然而,某些类型特别擅长在 panic 边界之间传递值。
如果这些类型目睹了 panic,它们可能会选择显式地中毒自己。中毒并不意味着任何特定的事情。通常,它只是意味着阻止正常使用继续进行。最明显的例子是标准库的 Mutex 类型。如果一个 MutexGuard (在获取锁时返回的东西) 在 panic 期间被 drop,则 Mutex 将会中毒。任何未来尝试锁定 Mutex 的操作都将返回 Err
或 panic。
Mutex 中毒并不是为了 Rust 通常关心的真正安全。它中毒是一种安全保护措施,防止盲目地使用从一个在被锁定时目睹了 panic 的 Mutex 中取出的数据。此类 Mutex 中的数据可能正在被修改,因此可能处于不一致或不完整的状态。重要的是要注意,如果该类型编写正确,则不能用它来违反内存安全性。毕竟,它必须具有最小的异常安全性!
但是,如果 Mutex 包含一个实际上不具有堆属性的 BinaryHeap,则任何使用它的代码都不太可能达到作者的预期。因此,程序不应正常运行。不过,如果你非常确定可以使用该值执行某些操作,则 Mutex 会公开一个方法来获取锁。毕竟,它是安全的。只是可能毫无意义。