这种稍微修饰的R c()为1.是同步,但不是发送,对吗? [英] This slightly modified Rc<()> is Sync, but not Send, right?

查看:59
本文介绍了这种稍微修饰的R c()为1.是同步,但不是发送,对吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我搜索的是Sync而不是Send的类型,因为它通常看起来一个特征是另一个特征的超集(实现Sync的每种类型都实现了Send" ).我发现此问题,但是唯一的答案确实很复杂.

I've searched for types that are Sync, but not Send, because it often looks like one trait is a superset of the other one ("every type that implements Sync also implements Send"). I've found this question, but the only real answer is really complicated.

所以我想出了这段代码:

So I've come up with this code:

struct Foo(Rc<()>);  // <-- private field

impl Foo {
    fn my_clone(&mut self) -> Self {  // <-- mutable borrow
        Foo(self.0.clone())
    }
}

我知道编译器不会自动为我的类型实现SendSync;但我对自己可以安全实施的 感兴趣.我认为:

I know that the compiler won't automatically implement Send nor Sync for my type; but I'm interested in what I could safely implement manually. I think:

  • 它应该能够实现Sync :对Foo不可变引用不会让我们对其进行任何处理(因为我们只能通过可变/专有引用调用my_clone()).不做任何事情,什么都不会出错,对吧?

  • It should be able to implement Sync: having an immutable reference to Foo won't let us do anything with it (because we can only call my_clone() via mutable/exclusive reference). And without doing anything, nothing can go wrong, right?

它应该不能能够实现Send :我们可以在主线程中克隆Foo(在启动另一个线程之前)以获得第二个对象.现在,两个对象共享一些内存(引用计数,存储在Cell<usize>中).如果我现在可以将这些对象之一发送到另一个线程,则两个线程都将拥有Foo的所有权,并引用相同的内存.因此,这两个对象可以同时调用my_clone(),从而导致对引用计数的同时,不同步,可变访问(数据竞争).

It should not be able to implement Send: we can clone our Foo in the main thread (before starting another thread) to get a second object. Now both objects share some memory (the reference count, stored in a Cell<usize>). If I now could send one of those objects to another thread, both threads would have ownership of a Foo, referencing the same memory. Thus both objects could call my_clone() at the same time, leading to simultaneous, unsynchronized, mutable access to the reference count (a data race).

这个推理是正确的还是我遗漏了一些东西?

Is this reasoning correct or am I missing something?

推荐答案

我知道编译器不会自动为我的类型实现SendSync.

实际上,只有在编译器可以确定这样做安全的情况下,编译器才会自动为您实现SendSync.

Indeed, the compiler automatically implements Send and Sync for you, only when it can determine it is safe to do so.

这个小程序:

use std::cell::Cell;
use std::sync::atomic::AtomicUsize;

fn ensure_sync<T: Sync>(_: T) {}

struct Automatic(AtomicUsize);

impl Automatic {
    fn new() -> Automatic { Automatic(AtomicUsize::new(0)) }
}

fn main() {
    ensure_sync(AtomicUsize::new(0));
    ensure_sync(Automatic::new());
    ensure_sync(Cell::new(0));
}

只有错误出现在Cell::new(0)行上,AutomaticSync,因为它的所有字段都是Sync.

Only errors out on the Cell::new(0) line, Automatic is Sync because all its fields are Sync.

关于FooRc既不是Sync也不是Send,因此实际上编译器也不会为您实现.

Regarding Foo, Rc is neither Sync nor Send, so indeed the compiler will not implement either for you.

Foo可以为Sync吗?

相信 1 .只要不对基于不变引用的模块添加任何其他操作即可.现在或将来.

I believe1 so. As long as NO other operation is added to the module that operate on immutable references. Now or in the future.

Foo可以是Send吗?

我同意您的结论,但我认为您错过了修改Cell的另一种方法:drop.

I agree with your conclusion, but I think you missed another method that modifies the Cell: drop.

因此,实际上,您似乎通过使用Send而不是Sync的基础类型想出了Sync而不是Send的类型.这可能是我的书呆子感觉,我觉得这很有趣:)

So, indeed, you seem to have come up with a type that is Sync and not Send, by using an underlying type that is Send and not Sync. It may be my nerd sense, I find it quite amusing :)

1 在处理unsafe代码时,我一无所知.仅仅因为很小的一个小细节就引起了人们的注意,就很容易自欺欺人以为是安全的.

1 When dealing with unsafe code, I am never sure of anything. It's very easy to fool oneself into thinking something is safe, simply because a tiny little detail escaped attention.

这篇关于这种稍微修饰的R c()为1.是同步,但不是发送,对吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆