我正在尝试实现一个非常幼稚的线程池模型。目前线程池的职责是:
create一个新线程并返回对其的引用我的主要问题是,上述要求迫使我让线程池保留一些HashMap<Id, Thread>线程,但也在创建线程时提供对线程的引用。
最重要的是,我需要能够从任何线程内部调用线程池的方法,从而有效地最终改变 1 个或多个线程(调用者和目标)。
这是一个非功能性的实现:
use std::collections::HashMap;
use std::cell::RefCell;
type Id = u32;
type ThreadPoolRef = RefCell<ThreadPool>;
#[derive(Debug)]
struct ThreadPool {
pool: HashMap<Id, RefCell<Thread>>,
id_count: Id
}
impl ThreadPool {
fn new() -> ThreadPool {
ThreadPool {
pool: HashMap::new(),
id_count: 1
}
}
fn create(&mut self) -> &RefCell<Thread> {
let thread: RefCell<Thread> =
RefCell::new(
Thread::new(self.id_count, RefCell::new(self))
);
self.id_count = self.id_count + 1;
self.pool.insert(self.id_count, thread);
self.pool.get(&self.id_count).unwrap()
}
}
#[derive(Debug, Clone)]
struct Thread {
id: Id,
pool: ThreadPoolRef
}
impl Thread {
fn new(id: Id, pool: ThreadPoolRef) -> Thread {
Thread {
id: id,
pool: pool
}
}
}
fn main() {
let thread_pool = ThreadPool::new();
let thread1 = thread_pool.create();
let thread2 = thread_pool.create();
// The final goal is to call thread1.method()
// that mutates thread1 and calls thread_pool.method2()
// which in turn will call thread2.method3() that will effectively
// mutate thread 2
}
Run Code Online (Sandbox Code Playgroud)
我尝试了几件事,例如使用RefCell但我开始收到很多生命周期参数丢失错误。
这是一个精简版本,我希望它是最容易解释的。
我需要能够从任何线程内部调用线程池的方法
这就要求线程池数据采用互斥机制,比如Mutexor RwLock(RefCell不适合多线程情况,参见书籍)。此外,每个线程必须保留对线程池数据的引用,因为线程池存储线程,这会产生问题。为了解决这个问题,我们可以将线程池数据放在一个an中Arc,并在每个线程中存储Weak对它的引用。请注意,我们使用弱引用来避免引用循环。
这实际上最终会改变 1 个或多个线程(调用者和目标)。
这就要求线程数据采用互斥机制。为了最终确定需求,请注意,由于线程池数据位于 a 中Mutex,因此我们无法返回对线程的引用(这需要保持线程池数据锁定),因此我们还将线程数据放入 a 中Arc。
Mutex这是使用(Playground )实现的示例:
use std::collections::HashMap;
use std::sync::{Arc, Weak, Mutex};
type Id = u32;
struct ThreadPool {
inner: Arc<Mutex<ThreadPoolInner>>,
}
struct ThreadPoolInner {
pool: HashMap<Id, Arc<Mutex<ThreadInner>>>,
id_count: Id,
}
impl ThreadPool {
fn new() -> ThreadPool {
let inner = ThreadPoolInner {
pool: HashMap::new(),
id_count: 0,
};
ThreadPool { inner: Arc::new(Mutex::new(inner)) }
}
fn create(&self) -> Thread {
let mut inner = self.inner.lock().unwrap();
let thread = Thread {
inner: Arc::new(Mutex::new(ThreadInner {
id: inner.id_count,
pool: Arc::downgrade(&self.inner),
})),
};
inner.id_count += 1;
let id = inner.id_count;
inner.pool.insert(id, thread.inner.clone());
thread
}
fn get(&self, id: Id) -> Option<Thread> {
let inner = self.inner.lock().unwrap();
inner.pool.get(&id).map(|t| Thread { inner: t.clone() })
}
fn some_mut_method(&self) {
let _inner = self.inner.lock().unwrap();
println!("something with pool");
}
}
struct Thread {
inner: Arc<Mutex<ThreadInner>>,
}
impl Thread {
fn get_pool(&self) -> Option<ThreadPool> {
let inner = self.inner.lock().unwrap();
// pool is a weak reference, upgrate try to get an Arc from it
inner.pool.upgrade().map(|inner| ThreadPool { inner: inner })
}
fn some_mut_method(&self) {
if let Some(pool) = self.get_pool() {
pool.some_mut_method();
let _t2 = pool.get(2).unwrap();
println!("something with t2");
}
}
}
#[derive(Clone)]
struct ThreadInner {
id: Id,
pool: Weak<Mutex<ThreadPoolInner>>,
}
fn main() {
let pool = ThreadPool::new();
let t1 = pool.create();
let _t2 = pool.create();
t1.some_mut_method();
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1418 次 |
| 最近记录: |