]> git.proxmox.com Git - rustc.git/blob - src/doc/nomicon/src/arc-mutex/arc-drop.md
New upstream version 1.55.0+dfsg1
[rustc.git] / src / doc / nomicon / src / arc-mutex / arc-drop.md
1 # Dropping
2
3 We now need a way to decrease the reference count and drop the data once it is
4 low enough, otherwise the data will live forever on the heap.
5
6 To do this, we can implement `Drop`.
7
8 Basically, we need to:
9
10 1. Decrement the reference count
11 2. If there is only one reference remaining to the data, then:
12 3. Atomically fence the data to prevent reordering of the use and deletion of
13 the data
14 4. Drop the inner data
15
16 First, we'll need to get access to the `ArcInner`:
17
18 <!-- ignore: simplified code -->
19 ```rust,ignore
20 let inner = unsafe { self.ptr.as_ref() };
21 ```
22
23 Now, we need to decrement the reference count. To streamline our code, we can
24 also return if the returned value from `fetch_sub` (the value of the reference
25 count before decrementing it) is not equal to `1` (which happens when we are not
26 the last reference to the data).
27
28 <!-- ignore: simplified code -->
29 ```rust,ignore
30 if inner.rc.fetch_sub(1, Ordering::Relaxed) != 1 {
31 return;
32 }
33 ```
34
35 We then need to create an atomic fence to prevent reordering of the use of the
36 data and deletion of the data. As described in [the standard library's
37 implementation of `Arc`][3]:
38 > This fence is needed to prevent reordering of use of the data and deletion of
39 > the data. Because it is marked `Release`, the decreasing of the reference
40 > count synchronizes with this `Acquire` fence. This means that use of the data
41 > happens before decreasing the reference count, which happens before this
42 > fence, which happens before the deletion of the data.
43 >
44 > As explained in the [Boost documentation][1],
45 >
46 > > It is important to enforce any possible access to the object in one
47 > > thread (through an existing reference) to *happen before* deleting
48 > > the object in a different thread. This is achieved by a "release"
49 > > operation after dropping a reference (any access to the object
50 > > through this reference must obviously happened before), and an
51 > > "acquire" operation before deleting the object.
52 >
53 > In particular, while the contents of an Arc are usually immutable, it's
54 > possible to have interior writes to something like a Mutex<T>. Since a Mutex
55 > is not acquired when it is deleted, we can't rely on its synchronization logic
56 > to make writes in thread A visible to a destructor running in thread B.
57 >
58 > Also note that the Acquire fence here could probably be replaced with an
59 > Acquire load, which could improve performance in highly-contended situations.
60 > See [2].
61 >
62 > [1]: https://www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html
63 > [2]: https://github.com/rust-lang/rust/pull/41714
64 [3]: https://github.com/rust-lang/rust/blob/e1884a8e3c3e813aada8254edfa120e85bf5ffca/library/alloc/src/sync.rs#L1440-L1467
65
66 To do this, we do the following:
67
68 ```rust
69 # use std::sync::atomic::Ordering;
70 use std::sync::atomic;
71 atomic::fence(Ordering::Acquire);
72 ```
73
74 Finally, we can drop the data itself. We use `Box::from_raw` to drop the boxed
75 `ArcInner<T>` and its data. This takes a `*mut T` and not a `NonNull<T>`, so we
76 must convert using `NonNull::as_ptr`.
77
78 <!-- ignore: simplified code -->
79 ```rust,ignore
80 unsafe { Box::from_raw(self.ptr.as_ptr()); }
81 ```
82
83 This is safe as we know we have the last pointer to the `ArcInner` and that its
84 pointer is valid.
85
86 Now, let's wrap this all up inside the `Drop` implementation:
87
88 <!-- ignore: simplified code -->
89 ```rust,ignore
90 impl<T> Drop for Arc<T> {
91 fn drop(&mut self) {
92 let inner = unsafe { self.ptr.as_ref() };
93 if inner.rc.fetch_sub(1, Ordering::Release) != 1 {
94 return;
95 }
96 // This fence is needed to prevent reordering of the use and deletion
97 // of the data.
98 atomic::fence(Ordering::Acquire);
99 // This is safe as we know we have the last pointer to the `ArcInner`
100 // and that its pointer is valid.
101 unsafe { Box::from_raw(self.ptr.as_ptr()); }
102 }
103 }
104 ```