这种稍微修饰的R c()为1.是同步,但不是发送,对吗? [英] This slightly modified Rc<()> is Sync, but not Send, right?
问题描述
我搜索的是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())
}
}
我知道编译器不会自动为我的类型实现Send
或Sync
;但我对自己可以安全实施的 感兴趣.我认为:
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 toFoo
won't let us do anything with it (because we can only callmy_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?
推荐答案
我知道编译器不会自动为我的类型实现
Send
或Sync
.
实际上,只有在编译器可以确定这样做安全的情况下,编译器才会自动为您实现Send
和Sync
.
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)
行上,Automatic
是Sync
,因为它的所有字段都是Sync
.
Only errors out on the Cell::new(0)
line, Automatic
is Sync
because all its fields are Sync
.
关于Foo
,Rc
既不是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屋!