如何设计可变的 Mutex 集合?
How to design a mutable collection of Mutex?
我需要一个 Mutex
的可变集合,需要在多个线程之间共享。此集合的目的是 return 给定键 MutexGuard
的列表(以便能够根据键同步线程)。请注意,初始化时,集合中没有 Mutex
,这些需要在运行时根据键创建。
我的代码如下:
use std::collections::HashMap;
use std::sync::{Arc, Mutex, MutexGuard};
struct Bucket {
locks: HashMap<String, Mutex<()>>,
}
impl Bucket {
// This method will create and add one or multiple Mutex to the
// collection (therefore it needs to take self as mutable), according
// to the give key (if the Mutex already exist it will just return
// its MutexGuard).
fn get_guards(
&mut self,
key: impl Into<String>,
) -> Vec<MutexGuard<'_, ()>> {
let lock = self.locks.entry(key.into()).or_default();
vec![lock.lock().unwrap()]
}
}
impl Default for Bucket {
fn default() -> Self {
Self {
locks: HashMap::new(),
}
}
}
fn main() {
// I need to wrap the bucket in a Arc<Mutex> since it's going to be shared
// between multiple threads
let mut bucket = Arc::new(Mutex::new(Bucket::default()));
// Here I need to get a list of guards, so that until they are dropped
// I can synchronize multiple threads with the same key (or to be more
// precise with the same MutexGuards, as different keys may yields the
// same MutexGuards).
let guards = {
// IMPORTANT: I need to unlock the Mutex used for the `bucket` (with
// write access) asap, otherwise it will nullify the purpose of the
// bucket, since the write lock would be hold for the whole `guards`
// scope.
let mut b = bucket.lock().unwrap();
b.get_guards("key")
};
}
我收到的错误如下:
error[E0597]: `b` does not live long enough
--> src/main.rs:29:9
|
27 | let _guards = {
| ------- borrow later stored here
28 | let mut b = bucket.lock().unwrap();
29 | b.get_guards("key")
| ^ borrowed value does not live long enough
30 | };
| - `b` dropped here while still borrowed
error: aborting due to previous error
有没有一种方法可以设计我的 Bucket
个 Mutex
集合,以便实现我的目标?
基本上你想从一个锁定的对象中借用一个对象并在它的封闭对象被解锁后保留它。
在这种情况下不可能进行非静态借用,因为这不安全,例如,任何其他线程都可能会删除您创建的对象的所有者以前借过.
根据您的逻辑,内部 locks
需要在其他线程之间安全共享您需要用 Arc
包装您的 mutexes
。
struct Bucket {
locks: HashMap<String, Arc<Mutex<()>>>,
}
这将 return 内部互斥体的原子引用。
//previously get_guards
fn get_mutexes(&mut self, key: impl Into<String>) -> Vec<Arc<Mutex<()>>> {
let lock = self.locks.entry(key.into()).or_default();
vec![lock.clone()]
}
您可以像这样简单地锁定所有需要的互斥量:
let mutexes = bucket.lock().unwrap().get_mutexes("key"); // locks(borrows bucket's guard) temporarily in here
let guards: Vec<MutexGuard<'_, ()>> =
mutexes.iter().map(|guard| guard.lock().unwrap()).collect();
请在 Playground
上查看完整代码
我需要一个 Mutex
的可变集合,需要在多个线程之间共享。此集合的目的是 return 给定键 MutexGuard
的列表(以便能够根据键同步线程)。请注意,初始化时,集合中没有 Mutex
,这些需要在运行时根据键创建。
我的代码如下:
use std::collections::HashMap;
use std::sync::{Arc, Mutex, MutexGuard};
struct Bucket {
locks: HashMap<String, Mutex<()>>,
}
impl Bucket {
// This method will create and add one or multiple Mutex to the
// collection (therefore it needs to take self as mutable), according
// to the give key (if the Mutex already exist it will just return
// its MutexGuard).
fn get_guards(
&mut self,
key: impl Into<String>,
) -> Vec<MutexGuard<'_, ()>> {
let lock = self.locks.entry(key.into()).or_default();
vec![lock.lock().unwrap()]
}
}
impl Default for Bucket {
fn default() -> Self {
Self {
locks: HashMap::new(),
}
}
}
fn main() {
// I need to wrap the bucket in a Arc<Mutex> since it's going to be shared
// between multiple threads
let mut bucket = Arc::new(Mutex::new(Bucket::default()));
// Here I need to get a list of guards, so that until they are dropped
// I can synchronize multiple threads with the same key (or to be more
// precise with the same MutexGuards, as different keys may yields the
// same MutexGuards).
let guards = {
// IMPORTANT: I need to unlock the Mutex used for the `bucket` (with
// write access) asap, otherwise it will nullify the purpose of the
// bucket, since the write lock would be hold for the whole `guards`
// scope.
let mut b = bucket.lock().unwrap();
b.get_guards("key")
};
}
我收到的错误如下:
error[E0597]: `b` does not live long enough
--> src/main.rs:29:9
|
27 | let _guards = {
| ------- borrow later stored here
28 | let mut b = bucket.lock().unwrap();
29 | b.get_guards("key")
| ^ borrowed value does not live long enough
30 | };
| - `b` dropped here while still borrowed
error: aborting due to previous error
有没有一种方法可以设计我的 Bucket
个 Mutex
集合,以便实现我的目标?
基本上你想从一个锁定的对象中借用一个对象并在它的封闭对象被解锁后保留它。
在这种情况下不可能进行非静态借用,因为这不安全,例如,任何其他线程都可能会删除您创建的对象的所有者以前借过.
根据您的逻辑,内部 locks
需要在其他线程之间安全共享您需要用 Arc
包装您的 mutexes
。
struct Bucket {
locks: HashMap<String, Arc<Mutex<()>>>,
}
这将 return 内部互斥体的原子引用。
//previously get_guards
fn get_mutexes(&mut self, key: impl Into<String>) -> Vec<Arc<Mutex<()>>> {
let lock = self.locks.entry(key.into()).or_default();
vec![lock.clone()]
}
您可以像这样简单地锁定所有需要的互斥量:
let mutexes = bucket.lock().unwrap().get_mutexes("key"); // locks(borrows bucket's guard) temporarily in here
let guards: Vec<MutexGuard<'_, ()>> =
mutexes.iter().map(|guard| guard.lock().unwrap()).collect();
请在 Playground
上查看完整代码