rust-lang / nomicon

The Dark Arts of Advanced and Unsafe Rust Programming
https://doc.rust-lang.org/nomicon/
Apache License 2.0
1.74k stars 256 forks source link

10.1.2. Base Code / Send and Sync. "Sync + Send" #436

Open kuzminrobin opened 6 months ago

kuzminrobin commented 6 months ago

10.1.2. Base Code / Send and Sync. Fragment:

unsafe impl<T: Sync + Send> Send for Arc<T> {}
unsafe impl<T: Sync + Send> Sync for Arc<T> {}

It is unclear from the text of the book why the line about Send has the fragment Sync +:

unsafe impl<T: Sync + Send> Send for Arc {}

and why the line about Sync has a fragment + Send:

unsafe impl<T: Sync + Send> Sync for Arc {}

Would be nice to see in the book the clarification or details about that.


I also looked at (and it is still unclear)

SOF3 commented 6 months ago
let v = Arc::new(Unsync);
let clone = v.clone();
thread::spawn(move || {
    clone.reference()
});
v.reference() // races with clone.reference()

Therefore Arc<Unsync> cannot be Send to prevent the cloned arc from being sent to another thread.

Similarly, Arc<Unsend> cannot be Sync to prevent getting cloned in another thread:

let v = Arc::new(Unsend);
worker.run(|| { // this closure only sends `&v` to the worker thread
    thread_local.set(v.clone());
});
drop(v);
worker.run(|| {
    let arc = thread_local.get();
    let unsend = arc.into_inner();
    drop(unsend); // we have somehow sent Unsend into the worker thread
});

The principle is that Arc can be used both by reference (by cloning) and by moving (by obviously sending the Arc), but its underlying reference can also be used as reference (normal Deref) and owned (by into_inner or otherwise becoming the owning reference after all other arcs are dropped).

kuzminrobin commented 6 months ago

@SOF3, thank you for your reply.

I assume that with Unsync and Unsend you mean values of types that are not Sync and not Send respectively.

I'm not sure what you mean with .reference() (I fail to find any docs about that) and intuitively I assume that you mean a pseudocode that deals with references to an Arc instance.

Having your reply I feel that I'm not mature enough in Rust to fully and clearly understand your explanation, such that I can explain the same to someone else. But the main point of this GitHub issue is not for me to understand, but to see the explanation in the book, the main words of this GitHub issue are: "Would be nice to see in the book the clarification or details about that".

Thanks.

SOF3 commented 6 months ago

.reference() refers to any placeholder function with a &self receiver.