Poisoning

尽管所有不安全的代码都必须确保其具有最小的异常安全,但并非所有类型都能确保最大的异常安全;而即使类型保证了,你的代码也可能导致额外的问题。例如,一个整数当然是异常安全的,但它本身没有语义。panic 的代码有可能无法正确地更新整数,从而产生不一致的程序状态。

通常是没问题的,因为任何见证异常的东西都会被销毁。例如,如果你发送一个 Vec 给另一个线程,而那个线程 panic 了,那么这个 Vec 是否处于一个奇怪的状态并不重要。它将被丢弃并永远消失。然而,有些类型特别擅长跨越 panic 边界获取值。

这些类型可以选择明确地 毒害(Poison) 自己,如果他们遇到了一个 panic。Poisoning 并不意味着什么特别的事情。一般来说,它只是意味着阻止正常的使用继续进行。这方面最明显的例子是标准库的 Mutex 类型。如果 Mutex 的一个 MutexGuards(当获得锁时返回的东西)在 panic 中被丢弃,Mutex 将自我中毒。今后任何试图锁定 Mutex 的行为都会返回Err或 panic。

Mutex 中毒不是为了 Rust 通常关心的真正的安全。它是作为一种安全防护措施,防止盲目地使用在锁定时发生了 panic 的 Mutex 中的数据。这样的 Mutex 中的数据可能正在被修改中,因此可能处于不一致或不完整的状态。需要注意的是,如果正确地编写了这样一个类型,就不会违反内存安全。毕竟,它必须是最低限度的异常安全的。

然而,如果 Mutex 包含,比如说,一个实际上不具备堆属性的 BinaryHeap,那么任何使用它的代码都不可能按照作者的意图运行。因此,程序不应该正常进行。不过,如果你确信你可以对这个值做一些事情,Mutex 还是暴露了一个方法来获得锁。毕竟,它安全的,只是可能是无稽之谈。