gpt4 book ai didi

thread-safety - 为什么 `Arc` 要求 T 既是 `Send` 又是 `Sync` 才能成为 `Send`/`Sync` 本身?

转载 作者:行者123 更新时间:2023-11-29 07:47:50 24 4
gpt4 key购买 nike

Arc<T> documentation说:

impl<T> Sync for Arc<T> where T: Send + Sync + ?Sized
impl<T> Send for Arc<T> where T: Send + Sync + ?Sized

Arc允许多个线程并发访问底层T通过不可变引用 &T .这是安全的,只要T不能通过 &T 以不同步的方式修改.对于具有“继承可变性”的所有类型(几乎所有类型)都是如此,对于具有非同步“内部可变性”(例如 RefCell ,... ).

据我了解,Send这里不需要绑定(bind)。例如,我认为分享my artificial type which implements Sync but not Send Arc是安全的。

最后,&T本身也没有这个绑定(bind)!在 Send 的文档中和 Sync 我们发现:

impl<'a, T> Send for &'a T where T: Sync + ?Sized
impl<'a, T> Sync for &'a T where T: Sync + ?Sized

作为Arc<T>允许对 T 进行相同的访问作为&T是的,我不明白为什么Arc<T>有额外的 Send边界。 这是为什么?

最佳答案

我相信这是因为 Arc 拥有它包含的值,因此负责删除它。

考虑以下顺序:

  • T 类型的值在线程 1 中创建。它不是Send,这意味着移动此值是安全的到另一个线程。
  • 这个值被移动到一个 Arc 句柄中。
  • 句柄的克隆被发送到线程 2。
  • 线程 1 存储的句柄被丢弃。
  • 线程 2 存储的句柄被丢弃。由于这是最后一个句柄,它会完全拥有存储值并将其删除。

就这样,我们将 T 类型的值从一个线程移动到另一个线程,这违反了内存安全。

&T 不需要Send,因为删除 &T never 允许您删除基础值。

附录:作为这会成为问题的类型的示例,请考虑类似 struct Handle(usize); 的类型,它由本地线程支持资源数组。如果这种类型的 Drop 实现在错误的线程上运行,这将导致它或者进行越界访问(它试图破坏一个此线程上不存在的资源),或销毁仍在使用的资源。

关于thread-safety - 为什么 `Arc<T>` 要求 T 既是 `Send` 又是 `Sync` 才能成为 `Send`/`Sync` 本身?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41909811/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com