为什么指向静态不可变变量的不可变指针不是 Sync?

poo*_*lie 3 multithreading rust

静态全局 C 字符串(如本答案中所示)没有Synctrait

pub static MY_STRING: &'static *const u8
  = "hello" as const *u8;

// TODO: Simple assertion showing it's not Sync ;)
Run Code Online (Sandbox Code Playgroud)

Sync 被描述为

准确的定义是:一个类型TSyncif&T是线程安全的。换句话说,&T在线程之间传递引用时不存在数据竞争的可能性。

看起来这完全是只读的并且具有静态生命周期,那么为什么传递引用不安全呢?

Fra*_*gné 5

本章发送和同步该Rustonomicon介绍这是什么意思的类型为SendSync。它提到:

  • 原始指针既不是发送也不是同步(因为它们没有安全防护)。

但这就是问题所在;为什么不*const T执行Sync?为什么安全卫士很重要?

就在这之前,它说:

发送和同步也是自动派生的特征。这意味着,与其他所有特征不同,如果一个类型完全由 Send 或 Sync 类型组成,那么它就是 Send 或 Sync。几乎所有的原语都是发送和同步,因此几乎所有你会与之交互的类型都是发送和同步。

这是原始指针既不是Send也不是 的关键原因Sync。如果您定义了一个封装原始指针的结构,但仅将其作为&T&mut T在结构的 API 中公开,您是否真的确保您的结构尊重Sendand的契约Sync?如果原始指针是Send,则默认情况下Rc<T>也将Send是 ,因此它必须明确选择退出。(在源代码中,实际上有一个明确的选择退出Rc<T>,但这仅用于文档目的,因为它实际上是多余的。)

[...] 它们是不安全的特性。这意味着它们实现起来是不安全的,其他不安全的代码可以假设它们被正确实现。

好的,让我们回顾一下:它们实施起来不安全,但它们是自动派生的。这不是一个奇怪的组合吗?事实上,它并不像听起来那么糟糕。大多数原始类型,如u32SendSync。简单地将原始值复合到 struct 或 enum 中不足以取消Sendor的类型Sync。因此,你需要一个结构或枚举与非Send或非Sync你需要编写一个之前unsafe impl

SendSync是标记特征,这意味着它们没有方法。因此,当函数或类型在类型参数上放置SendSync绑定时,它依赖该类型来遵守其所有 API 中的特定协定。因为这:

不正确地实现发送或同步会导致未定义行为。