Skip to content

Commit c2919c6

Browse files
ThePuzzlemakerGankra
authored andcommitted
Arc revisions (Clone atomic explanation) (pt2/3(+?))
1 parent e16ed7f commit c2919c6

File tree

2 files changed

+20
-17
lines changed

2 files changed

+20
-17
lines changed

src/arc-clone.md

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,22 @@ let inner = unsafe { self.ptr.as_ref() };
1313

1414
We can update the atomic reference count as follows:
1515
```rust,ignore
16-
let old_rc = inner.rc.fetch_add(1, Ordering::Relaxed);
16+
let old_rc = inner.rc.fetch_add(1, Ordering::???);
1717
```
1818

19-
As described in [the standard library's implementation of `Arc` cloning][2]:
20-
> Using a relaxed ordering is alright here, as knowledge of the original
21-
> reference prevents other threads from erroneously deleting the object.
22-
>
23-
> As explained in the [Boost documentation][1]:
24-
> > Increasing the reference counter can always be done with
25-
> > memory_order_relaxed: New references to an object can only be formed from an
26-
> > existing reference, and passing an existing reference from one thread to
27-
> > another must already provide any required synchronization.
28-
>
29-
> [1]: https://www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html
30-
[2]: https://github.com/rust-lang/rust/blob/e1884a8e3c3e813aada8254edfa120e85bf5ffca/library/alloc/src/sync.rs#L1171-L1181
19+
But what ordering should we use here? We don't really have any code that will
20+
need atomic synchronization when cloning, as we do not modify the internal value
21+
while cloning. Thus, we can use a Relaxed ordering here, which implies no
22+
happens-before relationship but is atomic. When `Drop`ping the Arc, however,
23+
we'll need to atomically synchronize when decrementing the reference count. This
24+
is described more in [the section on the `Drop` implementation for
25+
`Arc`](arc-drop.md) For more information on atomic relationships and Relaxed
26+
ordering, see [the section on atomics](atomics.md).
27+
28+
Thus, the code becomes this:
29+
```rust,ignore
30+
let old_rc = inner.rc.fetch_add(1, Ordering::Relaxed);
31+
```
3132

3233
We'll need to add another import to use `Ordering`:
3334
```rust,ignore
@@ -75,8 +76,9 @@ use std::sync::atomic::Ordering;
7576
impl<T> Clone for Arc<T> {
7677
fn clone(&self) -> Arc<T> {
7778
let inner = unsafe { self.ptr.as_ref() };
78-
// Using a relaxed ordering is alright here as knowledge of the original
79-
// reference prevents other threads from wrongly deleting the object.
79+
// Using a relaxed ordering is alright here as we don't need any atomic
80+
// synchronization here as we're not modifying or accessing the inner
81+
// data.
8082
let old_rc = inner.rc.fetch_add(1, Ordering::Relaxed);
8183
8284
if old_rc >= isize::MAX as usize {

src/arc-final.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,9 @@ impl<T> Deref for Arc<T> {
4949
impl<T> Clone for Arc<T> {
5050
fn clone(&self) -> Arc<T> {
5151
let inner = unsafe { self.ptr.as_ref() };
52-
// Using a relaxed ordering is alright here as knowledge of the original
53-
// reference prevents other threads from wrongly deleting the object.
52+
// Using a relaxed ordering is alright here as we don't need any atomic
53+
// synchronization here as we're not modifying or accessing the inner
54+
// data.
5455
let old_rc = inner.rc.fetch_add(1, Ordering::Relaxed);
5556

5657
if old_rc >= isize::MAX as usize {

0 commit comments

Comments
 (0)