Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign up`Arc` should only require `Sync`, not `Send` #20257
Comments
This comment has been minimized.
This comment has been minimized.
|
I guess the new way things are defined, |
This comment has been minimized.
This comment has been minimized.
|
Now that we have opt-in Send/Sync I think that this should be quite easy to encode (the latter I also agree that the bounds on construction and other functions can all be removed once these are in place. |
This comment has been minimized.
This comment has been minimized.
|
#20119 not only relaxed the I failed at giving a better explanation in the commit message but, one of the main reasons behind this is that it is reasonable to have something ref-counted that never escapes the thread. I know @alexcrichton and @nikomatsakis have discussed this a bit more. As far as I can tell, the reasoning behind this change makes sense to me. Probably we need a new type ? |
This comment has been minimized.
This comment has been minimized.
|
Yeah, I saw that a bit after creating this issue. However, we do still require |
This comment has been minimized.
This comment has been minimized.
I should point out that this did cause some confusion to me about a week ago (i.e. within days after this was posted). I'm perfectly willing to admit that I might be weird in this respect, but I think that for pedagogical reasons it is useful to have pretty tight bounds, even if in practice most user types that implement Sync will also implement Send. |
kmcallister
added
A-libs
A-traits
labels
Jan 16, 2015
This comment has been minimized.
This comment has been minimized.
|
I believe making this change will cause the following data structure to become invalid: use std::marker::PhantomData;
use std::sync::Arc;
use std::sync::atomic::{AtomicPtr, Ordering};
use std::mem;
struct ArcCell<T> {
x: AtomicPtr<T>,
_marker: PhantomData<Arc<T>>,
}
impl<T> ArcCell<T> {
fn new(x: Arc<T>) -> ArcCell<T> {
ArcCell { x: AtomicPtr::new(unsafe {mem::transmute(x)}), _marker: PhantomData }
}
fn swap(&self, y: Arc<T>, order: Ordering) -> Arc<T> {
unsafe {
mem::transmute(self.x.swap(mem::transmute(y), order))
}
}
}Because it allows for destroying let cell = ArcCell::new(Arc::new(1));
thread::scoped(|| { // (or equivalent)
let a = cell.swap(Arc::new(2), Ordering::SeqCst);
assert_eq!(*a, 1);
// no other references, so `a` is destroyed here
})This could be fixed by having @rust-lang/libs (et al): are the bounds in existing trait implementations public guarantees for things like this, where they influence correctness? |
huonw
added
I-nominated
T-libs
labels
Sep 29, 2015
This comment has been minimized.
This comment has been minimized.
|
There is of course no way to test for this automatically. |
This comment has been minimized.
This comment has been minimized.
|
@huonw This is a pretty interesting form of negative reasoning. In some sense, this is what the "fundamental" attribute is meant to capture -- that it's a breaking change to implement the trait. I'm not sure yet what I think about it in this case. |
This comment has been minimized.
This comment has been minimized.
|
It must be Sending a |
This comment has been minimized.
This comment has been minimized.
|
@bluss FWIW, this isn't what |
This comment has been minimized.
This comment has been minimized.
|
One popular definition of ownership is Owner is who drops the value. and using the clone trick, you can drop the inner How is the ownership not moved if there is now an |
This comment has been minimized.
This comment has been minimized.
|
@bluss The ownership of What I'm saying is that sending a reference to an |
This comment has been minimized.
This comment has been minimized.
|
OK, clarifying a bit more from IRC:
So I agree with @bluss's overall conclusion that the bounds need to stay as they are. |
This comment has been minimized.
This comment has been minimized.
|
From discussion with @huonw: Assuming If a
Can this be correct? @aturon It's your scoped threads, so you make the rules |
This comment has been minimized.
This comment has been minimized.
|
@aturon convinced me that that argument doesn't hold up in the face of imagination: it's not that obvious (at least to me) that we can't construct some sort of thread scoping/cross-thread |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
Stack overflow! One too many uses of double negatives! Can you rephrase this? |
This comment has been minimized.
This comment has been minimized.
|
Even the unwrap method of sending a
#20257 (comment) implies that the let x = Arc::new(1);
let guard = thread::scoped(|| {
let y = x.clone();
});
// illegal, since `x` is still borrowed by `guard`
drop(x);
However, it may be possible to have a fancier API that does allow transferring a reference to a new thread, doing something with it, and then "releasing" any borrows while keeping some data on the new thread (some sort of partial scoped API, maybe). |
This comment has been minimized.
This comment has been minimized.
|
@huonw well for example I think you could stick it in thread-local-data, perhaps. |
This comment has been minimized.
This comment has been minimized.
|
Sorry, to be clear, I am assuming a |
alexcrichton
removed
the
I-nominated
label
Oct 7, 2015
This comment has been minimized.
This comment has been minimized.
|
Closing. While there are some interesting policy questions here (e.g., the exact definition of |
pythonesque commentedDec 27, 2014
The original justification for this was from issue #2788. I am pretty confident that this reasoning no longer applies, especially now that we have
Sync. The reason this is safe is thatArc<T>will not beSendunlessTis, and if you try to passArc<T>intospawn()withoutSendit won't work anyway.(Making
Arc<T>onlySendsometimes may not have been doable prior to unsafe traits, so this issue may have depended on #20119 being resolved. But I think the wayArcis defined this isn't true).