Add weak_count
and strong_count
to Rc and Arc
These functions allow you to see how many weak and strong references there are to an `Arc`, `Rc`, or an `rc::Weak`. Due to the design of `Arc` it is not possible to get the number of weak references of an arbitrary `arc::Weak`. Look in `arc.rs` for a more in-depth explanation. On `arc::Arc` and `arc::Weak` these operations are wait-free and atomic.
This commit is contained in:
parent
96c8f2b0c1
commit
4c36ad01e7
@ -117,6 +117,16 @@ impl<T> Arc<T> {
|
||||
// these contents.
|
||||
unsafe { &*self._ptr }
|
||||
}
|
||||
|
||||
/// Get the number of weak references to this value.
|
||||
#[inline]
|
||||
#[experimental]
|
||||
pub fn weak_count(&self) -> uint { self.inner().weak.load(atomic::SeqCst) - 1 }
|
||||
|
||||
/// Get the number of strong references to this value.
|
||||
#[inline]
|
||||
#[experimental]
|
||||
pub fn strong_count(&self) -> uint { self.inner().strong.load(atomic::SeqCst) }
|
||||
}
|
||||
|
||||
#[unstable = "waiting on stability of Clone"]
|
||||
@ -247,6 +257,29 @@ impl<T: Sync + Send> Weak<T> {
|
||||
// See comments above for why this is "safe"
|
||||
unsafe { &*self._ptr }
|
||||
}
|
||||
|
||||
// Why is there no `weak_count()`?
|
||||
//
|
||||
// It is not possible to determine the number of weak references with only a weak reference
|
||||
// accurately in a wait-free manner. This is because we have a data-race with the last strong
|
||||
// reference's `drop` method. If that operation pauses between decrementing the strong
|
||||
// reference count to 0 and removing the implicit weak reference that the strong references
|
||||
// share then we will incorrectly think there is one more weak reference then there really is.
|
||||
//
|
||||
// We cannot get around this without making parts of this object no longer wait-free, since we
|
||||
// would either need to use locks to get mutual exclusion with `drop` or make it so that the
|
||||
// weak and strong reference counts can be modified atomically together. The first option
|
||||
// destroys wait-freedom by adding a lock and the second (in addition to being annoying to
|
||||
// implement) would make many operations (at least `downgrade` and both `clone`s) go from being
|
||||
// wait-free to merely lock-free, as we would need to do a manual CAS loop to get around other
|
||||
// threads modifying the other value in each of these cases.
|
||||
|
||||
/// Get the number of strong references to this value.
|
||||
///
|
||||
/// If this function returns 0 then the value has been freed.
|
||||
#[inline]
|
||||
#[experimental]
|
||||
pub fn strong_count(&self) -> uint { self.inner().strong.load(atomic::SeqCst) }
|
||||
}
|
||||
|
||||
#[experimental = "Weak pointers may not belong in this module."]
|
||||
@ -465,6 +498,47 @@ mod tests {
|
||||
drop(arc_weak);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_strong_count() {
|
||||
let a = Arc::new(0u32);
|
||||
assert!(a.strong_count() == 1);
|
||||
let w = a.downgrade();
|
||||
assert!(a.strong_count() == 1);
|
||||
let b = w.upgrade().expect("");
|
||||
assert!(b.strong_count() == 2);
|
||||
assert!(a.strong_count() == 2);
|
||||
drop(w);
|
||||
drop(a);
|
||||
assert!(b.strong_count() == 1);
|
||||
let c = b.clone();
|
||||
assert!(b.strong_count() == 2);
|
||||
assert!(c.strong_count() == 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_weak_count() {
|
||||
let a = Arc::new(0u32);
|
||||
assert!(a.strong_count() == 1);
|
||||
assert!(a.weak_count() == 0);
|
||||
let w = a.downgrade();
|
||||
assert!(a.strong_count() == 1);
|
||||
assert!(w.strong_count() == 1);
|
||||
assert!(a.weak_count() == 1);
|
||||
drop(w);
|
||||
assert!(a.strong_count() == 1);
|
||||
assert!(a.weak_count() == 0);
|
||||
let c = a.clone();
|
||||
assert!(a.strong_count() == 2);
|
||||
assert!(a.weak_count() == 0);
|
||||
let d = c.downgrade();
|
||||
assert!(c.weak_count() == 1);
|
||||
assert!(c.strong_count() == 2);
|
||||
|
||||
drop(a);
|
||||
drop(c);
|
||||
drop(d);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn show_arc() {
|
||||
let a = Arc::new(5u32);
|
||||
|
@ -211,6 +211,16 @@ impl<T> Rc<T> {
|
||||
_noshare: marker::NoSync
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the number of weak references to this value.
|
||||
#[inline]
|
||||
#[experimental]
|
||||
pub fn weak_count(&self) -> uint { self.weak() - 1 }
|
||||
|
||||
/// Get the number of strong references to this value.
|
||||
#[inline]
|
||||
#[experimental]
|
||||
pub fn strong_count(&self) -> uint { self.strong() }
|
||||
}
|
||||
|
||||
/// Returns true if the `Rc` currently has unique ownership.
|
||||
@ -220,8 +230,7 @@ impl<T> Rc<T> {
|
||||
#[inline]
|
||||
#[experimental]
|
||||
pub fn is_unique<T>(rc: &Rc<T>) -> bool {
|
||||
// note that we hold both a strong and a weak reference
|
||||
rc.strong() == 1 && rc.weak() == 1
|
||||
rc.weak_count() == 0 && rc.strong_count() == 1
|
||||
}
|
||||
|
||||
/// Unwraps the contained value if the `Rc` has unique ownership.
|
||||
@ -424,6 +433,20 @@ impl<T> Weak<T> {
|
||||
Some(Rc { _ptr: self._ptr, _nosend: marker::NoSend, _noshare: marker::NoSync })
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the number of weak references to this value.
|
||||
#[inline]
|
||||
#[experimental]
|
||||
pub fn weak_count(&self) -> uint {
|
||||
if self.strong() != 0 { self.weak() - 1 } else { self.weak() }
|
||||
}
|
||||
|
||||
/// Get the number of strong references to this value.
|
||||
///
|
||||
/// If this function returns 0 then the value has been freed.
|
||||
#[inline]
|
||||
#[experimental]
|
||||
pub fn strong_count(&self) -> uint { self.strong() }
|
||||
}
|
||||
|
||||
#[unsafe_destructor]
|
||||
@ -566,6 +589,40 @@ mod tests {
|
||||
assert!(super::is_unique(&x));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_strong_count() {
|
||||
let a = Rc::new(0u32);
|
||||
assert!(a.strong_count() == 1);
|
||||
let w = a.downgrade();
|
||||
assert!(a.strong_count() == 1);
|
||||
let b = w.upgrade().expect("upgrade of live rc failed");
|
||||
assert!(b.strong_count() == 2);
|
||||
assert!(a.strong_count() == 2);
|
||||
drop(w);
|
||||
drop(a);
|
||||
assert!(b.strong_count() == 1);
|
||||
let c = b.clone();
|
||||
assert!(b.strong_count() == 2);
|
||||
assert!(c.strong_count() == 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_weak_count() {
|
||||
let a = Rc::new(0u32);
|
||||
assert!(a.strong_count() == 1);
|
||||
assert!(a.weak_count() == 0);
|
||||
let w = a.downgrade();
|
||||
assert!(a.strong_count() == 1);
|
||||
assert!(w.weak_count() == 1);
|
||||
drop(w);
|
||||
assert!(a.strong_count() == 1);
|
||||
assert!(a.weak_count() == 0);
|
||||
let c = a.clone();
|
||||
assert!(a.strong_count() == 2);
|
||||
assert!(a.weak_count() == 0);
|
||||
assert!(c.downgrade().weak_count() == 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn try_unwrap() {
|
||||
let x = Rc::new(3u);
|
||||
|
Loading…
x
Reference in New Issue
Block a user