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