|
|
@ -258,11 +258,11 @@ std::marker::Send` is not satisfied
|
|
|
|
|
|
|
|
|
|
|
|
哇哦,太长不看!说重点:第一个提示表明 `Rc<Mutex<i32>>` 不能安全的在线程间传递。理由也在错误信息中,“不满足 `Send` trait bound”(`the trait bound Send is not satisfied`)。下一部分将会讨论 `Send`,它是确保许多用在多线程中的类型,能够适合并发环境的 trait 之一。
|
|
|
|
哇哦,太长不看!说重点:第一个提示表明 `Rc<Mutex<i32>>` 不能安全的在线程间传递。理由也在错误信息中,“不满足 `Send` trait bound”(`the trait bound Send is not satisfied`)。下一部分将会讨论 `Send`,它是确保许多用在多线程中的类型,能够适合并发环境的 trait 之一。
|
|
|
|
|
|
|
|
|
|
|
|
不幸的是,`Rc<T>` 并不能安全的在线程间共享。当 `Rc<T>` 管理引用计数时,它必须在每一个 `clone` 调用时增加计数,并在每一个克隆被丢弃时减少计数。`Rc<T>` 并没有使用任何并发原语,来确保改变计数的操作不会被其他线程打断。在计数出错时可能会导致诡异的 bug,比如可能会造成内存泄漏,或在使用结束之前就丢弃一个值。那么如果有一个正好与 `Rc<T>` 类似,而又以一种线程安全的方式改变引用计数的类型会怎么样呢?
|
|
|
|
不幸的是,`Rc<T>` 并不能安全的在线程间共享。当 `Rc<T>` 管理引用计数时,它必须在每一个 `clone` 调用时增加计数,并在每一个克隆被丢弃时减少计数。`Rc<T>` 并没有使用任何并发原语,来确保改变计数的操作不会被其他线程打断。在计数出错时可能会导致诡异的 bug,比如可能会造成内存泄漏,或在使用结束之前就丢弃一个值。如果有一个类型与 `Rc<T>` 相似,又以一种线程安全的方式改变引用计数,会怎么样呢?
|
|
|
|
|
|
|
|
|
|
|
|
#### 原子引用计数 `Arc<T>`
|
|
|
|
#### 原子引用计数 `Arc<T>`
|
|
|
|
|
|
|
|
|
|
|
|
如果你想过之前的问题,答案是肯定的,确实有一个类似`Rc<T>`并可以安全的用于并发环境的类型:`Arc<T>`。字母“a”代表**原子性**(*atomic*),所以这是一个**原子引用计数**(*atomically reference counted*)类型。原子性是另一类这里还未涉及到的并发原语;请查看标准库中`std::sync::atomic`的文档来获取更多细节。其中的要点就是:原子性类型工作起来类似原始类型,不过可以安全的在线程间共享。
|
|
|
|
答案是肯定的,确实有一个类似`Rc<T>`并可以安全的用于并发环境的类型:`Arc<T>`。字母“a”代表**原子性**(*atomic*),所以这是一个**原子引用计数**(*atomically reference counted*)类型。原子性是另一类这里还未涉及到的并发原语;请查看标准库中`std::sync::atomic`的文档来获取更多细节。其中的要点就是:原子性类型工作起来类似原始类型,不过可以安全的在线程间共享。
|
|
|
|
|
|
|
|
|
|
|
|
为什么不是所有的原始类型都是原子性的?为什么不是所有标准库中的类型都默认使用`Arc<T>`实现?线程安全带来性能惩罚,我们希望只在必要时才为此买单。如果只是在单线程中对值进行操作,原子性提供的保证并无必要,代码可以因此运行的更快。
|
|
|
|
为什么不是所有的原始类型都是原子性的?为什么不是所有标准库中的类型都默认使用`Arc<T>`实现?线程安全带来性能惩罚,我们希望只在必要时才为此买单。如果只是在单线程中对值进行操作,原子性提供的保证并无必要,代码可以因此运行的更快。
|
|
|
|
|
|
|
|
|
|
|
|