This program hangs, and I suspect it does not release the mutex lock as it is supposed to. I must be doing something wrong here, but I cannot put my finger on it.
use std::any::TypeId;
use std::collections::HashSet;
use std::marker::PhantomData;
use std::sync::{LazyLock, Mutex};
use unique::Unique;
static ID_SET: LazyLock<Mutex<HashSet<TypeId>>> = LazyLock::new(|| Mutex::new(HashSet::new()));
mod unique {
use super::*;
// Due to its private data member, outside this module,
// this struct can only be created using `new`.
pub struct Unique<O: 'static>(PhantomData<O>);
impl<O: 'static> Unique<O> {
pub fn id() -> TypeId {
TypeId::of::<O>()
}
pub fn new() -> Option<Self> {
let mut set = ID_SET.lock().unwrap();
dbg!(set.insert(Self::id())).then_some(Self(PhantomData))
}
}
impl<O: 'static> Drop for Unique<O> {
fn drop(&mut self) {
let mut set = ID_SET.lock().unwrap();
(!set.remove(&Self::id())).then(|| panic!("duplicity detected"));
}
}
}
fn main() {
struct TheOneRing;
let the_one_ring = Unique::<TheOneRing>::new().unwrap();
let the_two_ring = Unique::<TheOneRing>::new().unwrap();
panic!();
}
prints:
[src/main.rs:24:13] set.insert(Self::id()) = true
[src/main.rs:24:13] set.insert(Self::id()) = false
but then hangs...
I must be doing something wrong here, but I cannot put my finger on it.
pub fn new() -> Option<Self> {
let mut set = ID_SET.lock().unwrap();
dbg!(set.insert(Self::id())).then_some(Self(PhantomData))
}
then_some
is eager, so this effectively is
pub fn new() -> Option<Self> {
let mut set = ID_SET.lock().unwrap();
let v = Self(PhantomData);
dbg!(set.insert(Self::id())).then_some(v);
}
meaning if set.insert
returns false
, v
is dropped, which tries to acquire the lock, but the lock is already held by new
, thus deadlock.