|
|
@ -13,21 +13,22 @@ let inner = unsafe { self.ptr.as_ref() };
|
|
|
|
|
|
|
|
|
|
|
|
We can update the atomic reference count as follows:
|
|
|
|
We can update the atomic reference count as follows:
|
|
|
|
```rust,ignore
|
|
|
|
```rust,ignore
|
|
|
|
let old_rc = inner.rc.fetch_add(1, Ordering::Relaxed);
|
|
|
|
let old_rc = inner.rc.fetch_add(1, Ordering::???);
|
|
|
|
```
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
As described in [the standard library's implementation of `Arc` cloning][2]:
|
|
|
|
But what ordering should we use here? We don't really have any code that will
|
|
|
|
> Using a relaxed ordering is alright here, as knowledge of the original
|
|
|
|
need atomic synchronization when cloning, as we do not modify the internal value
|
|
|
|
> reference prevents other threads from erroneously deleting the object.
|
|
|
|
while cloning. Thus, we can use a Relaxed ordering here, which implies no
|
|
|
|
>
|
|
|
|
happens-before relationship but is atomic. When `Drop`ping the Arc, however,
|
|
|
|
> As explained in the [Boost documentation][1]:
|
|
|
|
we'll need to atomically synchronize when decrementing the reference count. This
|
|
|
|
> > Increasing the reference counter can always be done with
|
|
|
|
is described more in [the section on the `Drop` implementation for
|
|
|
|
> > memory_order_relaxed: New references to an object can only be formed from an
|
|
|
|
`Arc`](arc-drop.md) For more information on atomic relationships and Relaxed
|
|
|
|
> > existing reference, and passing an existing reference from one thread to
|
|
|
|
ordering, see [the section on atomics](atomics.md).
|
|
|
|
> > another must already provide any required synchronization.
|
|
|
|
|
|
|
|
>
|
|
|
|
Thus, the code becomes this:
|
|
|
|
> [1]: https://www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html
|
|
|
|
```rust,ignore
|
|
|
|
[2]: https://github.com/rust-lang/rust/blob/e1884a8e3c3e813aada8254edfa120e85bf5ffca/library/alloc/src/sync.rs#L1171-L1181
|
|
|
|
let old_rc = inner.rc.fetch_add(1, Ordering::Relaxed);
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
We'll need to add another import to use `Ordering`:
|
|
|
|
We'll need to add another import to use `Ordering`:
|
|
|
|
```rust,ignore
|
|
|
|
```rust,ignore
|
|
|
@ -75,8 +76,9 @@ use std::sync::atomic::Ordering;
|
|
|
|
impl<T> Clone for Arc<T> {
|
|
|
|
impl<T> Clone for Arc<T> {
|
|
|
|
fn clone(&self) -> Arc<T> {
|
|
|
|
fn clone(&self) -> Arc<T> {
|
|
|
|
let inner = unsafe { self.ptr.as_ref() };
|
|
|
|
let inner = unsafe { self.ptr.as_ref() };
|
|
|
|
// Using a relaxed ordering is alright here as knowledge of the original
|
|
|
|
// Using a relaxed ordering is alright here as we don't need any atomic
|
|
|
|
// reference prevents other threads from wrongly deleting the object.
|
|
|
|
// synchronization here as we're not modifying or accessing the inner
|
|
|
|
|
|
|
|
// data.
|
|
|
|
let old_rc = inner.rc.fetch_add(1, Ordering::Relaxed);
|
|
|
|
let old_rc = inner.rc.fetch_add(1, Ordering::Relaxed);
|
|
|
|
|
|
|
|
|
|
|
|
if old_rc >= isize::MAX as usize {
|
|
|
|
if old_rc >= isize::MAX as usize {
|
|
|
|