【问题标题】:how do I implement an id lock in rust?如何在 rust 中实现 id 锁定?
【发布时间】:2021-02-01 11:20:25
【问题描述】:

我必须锁定由 id 标识的不同进程。

所以我写了如下代码:

use std::collections::HashMap;
use std::ptr::null;
use std::sync::{Arc, Mutex, MutexGuard};

pub struct IDMutex {
    m: Mutex<HashMap<String, Arc<Mutex<u8>>>>,
}

pub struct IDMutexGuard<'a> {
    mutex: &'a IDMutex,
    local_mutex: Arc<Mutex<u8>>,
    local_guard: *const MutexGuard<'a, u8>,
    id: String,
}

impl<'a> IDMutexGuard<'a> {
    fn new(mutex: &'a IDMutex, id: String) -> Self {
        let mut guard: MutexGuard<'_, _> = mutex.m.lock().unwrap();
        let local_mutex = guard.entry(id.clone()).or_default().clone();

        let mut res = Self {
            mutex,
            id,
            local_mutex: local_mutex,
            local_guard: null(),
        };
        res.local_guard = &res.local_mutex.lock().unwrap();
        res
    }
}

impl<'a> Drop for IDMutexGuard<'a> {
    fn drop(&mut self) {
        drop(&mut self.local_guard);
        let mut guard = self.mutex.m.lock().unwrap();
        guard.remove(&self.id);
    }
}

impl IDMutex {
    fn lock(&self, id: String) -> IDMutexGuard<'_> {
        IDMutexGuard::new(&self, id)
    }
}

它的实现类似于标准库的 Mutex 和 MutexGuard,但带有一个 id 参数,以便我可以锁定一些 id。但由于借用了规则,它并没有构建。

那么有什么解决这些问题的想法吗?

我知道正确的方法是挑选出共享状态,然后使用标准库的互斥锁来锁定它们。但由于某些历史原因,这确实是一种具有挑战性的方式,我希望我将来会这样做。

【问题讨论】:

  • 从看它我完全不知道你的代码应该做什么,你能添加 soe cmets 吗?
  • 您能否更详细地解释一下您的用例?您正在询问解决问题的具体方法。我觉得这种方法比它需要的更复杂,但如果不了解潜在问题就很难说。
  • 锁定一个进程是什么意思?我以前没听过这句话,谷歌搜索也没有带来任何启发性的东西。通常我们谈论锁定资源,如文件和(对于线程)共享内存。直觉上我会假设锁定一个进程意味着暂停它,但我在你的代码中没有看到任何与多处理相关的东西,所以我想我一定是误解了。
  • 我可以肯定地说drop(&amp;mut self.local_guard) 没有做任何有用的事情。您需要 std::ptr::drop_in_place 将保护放在指针的另一端,并且您需要取消引用它。但这也是错误的,因为在new 中,指针被初始化为当new 返回时将被删除的局部变量的地址。所以这肯定不是你想要的。

标签: rust mutex


【解决方案1】:

那么对于解决这些问题有什么想法吗?

不要在现有的基础上创建自己的 MutexGuard。这实际上并不可行,因为您需要同时归还拥有的 Mutex 和 MutexGuard,因为后者借用了前者。此外,拥有的 Mutex 确实是从 Arc 借来的,因此您还需要返回 that。但是返回 Arc 的行为会移动它,这是不允许的,因为这样引用可能会失效。

也不要使用低级代码创建自己的 MutexGuard,这是可能的,但并不容易。

我看到了两种摆脱困境的方法:

  1. 使用基于回调的系统,让您的 API 管理锁,调用者提供一个 FnOnce,您使用该信息进行调用,这是非常有限的,但对于调用者和被调用者来说都非常简单。

  2. 返回您从映射中克隆的Arc,并让调用者处理锁定它。这非常重要,因为由于您的设置的设计方式,锁定地图、获取物品然后解锁地图是很正常的同时您仍然持有该物品,这意味着调用者可能想要到try_lock第二把锁。

【讨论】:

    猜你喜欢
    • 2021-10-17
    • 2012-11-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-06
    相关资源
    最近更新 更多