rust 仅实现Send和Sync之一的类型的示例有哪些?

o7jaxewo  于 2023-10-20  发布在  其他
关注(0)|答案(3)|浏览(97)

为了更好地理解SendSync特征,有没有这样的类型的例子:

  • 实现Send而不实现Sync
  • 实现Sync而不实现Send
doinxwow

doinxwow1#

首先,重要的是要认识到大多数结构(或枚举)是Send

  • 任何不包含任何引用的结构都可以是Send + 'static
  • 任何包含生存期下限为'a的引用的结构都可以是Send + 'a

因此,您通常会期望任何Syncstruct也是Send,因为Send是如此容易达到的标准(与Sync相比,Sync需要多个线程的安全并发修改)。
但是,没有什么可以阻止类型的创建者将其特别标记为not Send。例如,让我们复苏的条件!
在Lisp中,条件的概念是为给定的条件设置一个处理程序(比如:FileNotFound),然后当在堆栈深处满足此条件时,将调用处理程序。
如何在Rust中实现这一点?
为了保持线程的独立性,您可以为条件处理程序使用线程本地存储(参见std::thread_local!)。每个条件都是一个条件处理程序的堆栈,要么只调用最上面的一个,要么从最上面的一个开始迭代,直到一个成功。
但是,你会怎么设置它们呢?
我会用RAII!我会将条件处理程序绑定到线程本地堆栈中,并将其注册到框架中(例如,使用插入式双向链表作为堆栈)。
这样,当我完成时,条件处理程序会自动注销自己。
当然,系统必须考虑到用户做了意想不到的事情(比如将条件处理程序存储在堆中,而不是按照它们创建的顺序删除它们),这就是为什么我们使用双向链表,以便处理程序可以在必要时从堆栈中间取消注册。
所以我们有一个:

struct ConditionHandler<T> {
    handler: T,
    prev: Option<*mut ConditionHandler<T>>,
    next: Option<*mut ConditionHandler<T>>,
}

而“真实的”处理程序由用户作为T传递。
这个处理程序会是Sync吗?
可能,这取决于你如何创建它,但没有理由你不能创建一个处理程序,使它的引用不能在多个线程之间共享。

  • 注意:这些线程不能访问其prev/next数据成员,这些成员是私有的,不需要是Sync。*

这个处理程序会是Send吗?
除非特别小心,否则不会。
prevnext字段不受并发访问的保护,更糟糕的是,如果处理程序被删除,而另一个线程已经获得了对它的引用(例如,另一个处理程序试图取消注册),那么这个现在悬挂的引用将导致Undefined Behavior。

你有了它:如果TSync,则ConditionHandler<T>Sync,但永远不会是Send(原样)。
为了完整起见,许多类型实现了Send,但没有实现Sync(实际上,大多数Send类型):例如OptionVec

czfnxgou

czfnxgou2#

CellRefCell实现了Send,但没有实现Sync,因为它们可以在线程之间安全地发送,但不能在线程之间共享。

hi3rlvi2

hi3rlvi23#

对于Sync,我猜:https://doc.rust-lang.org/std/sync/struct.MutexGuard.html,它看起来不像是在上面实现了发送。
对于发送只有你有细胞的家庭。

相关问题