3 ms·
> 1) After some soul searching, it seems like the really important invariant to me is that all alive objects should be reachable from the stack(s) at any given
by dbaupp 11y ago
> 1) After some soul searching, it seems like the really important invariant to me is that all alive objects should be reachable from the stack(s) at any given moment. So I'm kind of okay with failing to run destructors due to deadlock or process exit, but not okay with leaking a cycle. Is that a sensible distinction, or is the situation even more subtle?
I think that's a reasonable distinction, but, at least for deadlocks, I'm not sure it is enough to have all the guarantees one might want (particularly around multithreading/scoping). Then again, it might be.
> 2) How do I make a cycle with Mutex and RWLock?
The same as a RefCell, just call `.lock().unwrap()` and `.write().unwrap()` instead of `.borrow_mut()`. These two types are essentially the same as a RefCell, just with more synchronisation, and fewer panics. They can block and wait for another thread to finish, at the risk of deadlocks of course, while a RefCell is restricted to a single thread, so blocking would just dead lock a thread with itself, hence a panic resolves the situation better. In fact, other than this blocking/panicking distinction, a RwLock and RefCell are almost identical: .read == .borrow and .write == .borrow_mut.
Here's a demo which creates cycles that contain a type that prints in the destructor (demonstrating that they don't run): https://play.rust-lang.org/?gist=6ea16b859e22f57fee14&version=stable&run=1 https://play.rust-lang.org/?gist=6ea16b859e22f57fee14&versio...
> 3) I don't completely understand the queue example, what exactly is the magic that allows self-reference?
This is also essentially the same as the core RefCell/Mutex example, replacing .borrow_mut()/.lock() with .send. An mpmc Queue<T> will be isomorphic to Arc<Mutex<VecDeque<T>>> (although unlikely to be implemented as such in practice). The key is that they will reference-count the book-keeping that needs to be shared among all handles (like the start/tail of the queue), which allows creating a reference cycle.