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 还是暴露了一个方法来获得锁。毕竟,它是安全的,只是可能是无稽之谈。