最终代码

这就是我们的最终代码,我在这里加了一些额外的注释并排序了一下 imports:

  1. use std::marker::PhantomData;
  2. use std::ops::Deref;
  3. use std::ptr::NonNull;
  4. use std::sync::atomic::{self, AtomicUsize, Ordering};
  5. pub struct Arc<T> {
  6. ptr: NonNull<ArcInner<T>>,
  7. phantom: PhantomData<ArcInner<T>>,
  8. }
  9. pub struct ArcInner<T> {
  10. rc: AtomicUsize,
  11. data: T,
  12. }
  13. impl<T> Arc<T> {
  14. pub fn new(data: T) -> Arc<T> {
  15. // 当前的指针就是第一个引用,因此初始时设置 count 为 1
  16. let boxed = Box::new(ArcInner {
  17. rc: AtomicUsize::new(1),
  18. data,
  19. });
  20. Arc {
  21. // 我们从 Box::into_raw 得到该指针,因此使用 `.unwrap()` 是完全可行的
  22. ptr: NonNull::new(Box::into_raw(boxed)).unwrap(),
  23. phantom: PhantomData,
  24. }
  25. }
  26. }
  27. unsafe impl<T: Sync + Send> Send for Arc<T> {}
  28. unsafe impl<T: Sync + Send> Sync for Arc<T> {}
  29. impl<T> Deref for Arc<T> {
  30. type Target = T;
  31. fn deref(&self) -> &T {
  32. let inner = unsafe { self.ptr.as_ref() };
  33. &inner.data
  34. }
  35. }
  36. impl<T> Clone for Arc<T> {
  37. fn clone(&self) -> Arc<T> {
  38. let inner = unsafe { self.ptr.as_ref() };
  39. // 我们没有修改 Arc 中的数据,因此在这里不需要任何原子的同步操作,
  40. // 使用 relax 这种排序方式也就完全可行
  41. let old_rc = inner.rc.fetch_add(1, Ordering::Relaxed);
  42. if old_rc >= isize::MAX as usize {
  43. std::process::abort();
  44. }
  45. Self {
  46. ptr: self.ptr,
  47. phantom: PhantomData,
  48. }
  49. }
  50. }
  51. impl<T> Drop for Arc<T> {
  52. fn drop(&mut self) {
  53. let inner = unsafe { self.ptr.as_ref() };
  54. if inner.rc.fetch_sub(1, Ordering::Release) != 1 {
  55. return;
  56. }
  57. // 我们需要防止针对 inner 的使用和删除的重排序
  58. // 因此使用 fence 来进行保护是非常有必要
  59. atomic::fence(Ordering::Acquire);
  60. // 安全保证:我们知道这是最后一个对 ArcInner 的引用,并且这个指针是有效的
  61. unsafe { Box::from_raw(self.ptr.as_ptr()); }
  62. }
  63. }