I\'m trying to implement a very naive Thread Pool model. For now the responsibilities of the thread pool are:
create
a new thread and return a referen
I need to be able to call methods of the thread pool from inside any thread
This requires that the thread pool data be in a mutual-exclusion mechanism, like Mutex or RwLock (RefCell
is not appropriate for multi-threaded situations, see the book). Besides, each thread must keep a reference to the thread pool data, as the thread pool stores the threads, this creates a problem. To solve this problem, we can put the thread pool data in an Arc and store a Weak reference to it in each thread. Note that we use weak references to avoid reference cycles.
that effectively end up mutating 1 or more threads (the caller and the targets).
This requires that the thread data be in a mutual-exclusion mechanism. To finalize the requirements, note that as the thread pool data is in a Mutex
, we cannot return references to threads (that would require keeping the thread pool data locked), so we also put thread data in a Arc
.
Here is an example of implementation using 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();
}