最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

rust - Why does this mutex that protects globally unique instantiations deadlock when attempting to create an already existing e

programmeradmin1浏览0评论

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...

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...

Share Improve this question edited Jan 31 at 19:42 kmdreko 62.1k6 gold badges95 silver badges164 bronze badges asked Jan 29 at 12:56 hkBsthkBst 3,39015 silver badges34 bronze badges 2
  • If you can use a BTreeSet instead, you can use a static without a LazyLock: play.rust-lang./… – Richard Neumann Commented Jan 29 at 14:04
  • @RichardNeumann, ah because it has a const new method, thanks! – hkBst Commented Jan 30 at 17:52
Add a comment  | 

1 Answer 1

Reset to default 5

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.

发布评论

评论列表(0)

  1. 暂无评论