Common Round Links in Rust

I am trying to implement a very naive thread pool model. Currently, the responsibility for the thread pool is:

  • create new thread and return a link to it
  • Save map of created threads
  • Mute threads according to various events caused by threads

My main problem is that the above requirement forces me to support the thread pool HashMap<Id, Thread> threads, but also provides a link to the threads when they are created.

In addition, I need to be able to call thread pool methods from within any thread that effectively ends mutating 1 or more threads (the caller and the targets).

Here is a non-functional implementation:

 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 } 

Rust play

I tried several things, for example, using RefCell , but I got a lot of lifetime parameters that are missing.

This is a stripped-down version, which, I believe, will be the easiest to explain.

+1
source share
1 answer

I need to be able to call thread pool methods from any thread

This requires that the thread pool data be in a mutual exclusion mechanism, such as Mutex or RwLock ( RefCell not suitable for multi-threaded situations, see the book ). In addition, each thread must contain a link to the thread pool data, since the thread pool stores the threads, which creates a problem. To solve this problem, we can put the thread pool data in Arc and keep Weak referencing it in each thread. Please note that we use weak references to avoid reference loops .

which effectively end up mutating 1 or more threads (the caller and the target).

This requires that the flow data be in a mutual exclusion mechanism. To complete the requirements, note that since the thread pool data is in Mutex , we cannot return stream references (for which you need to save the thread pool data), so we also put the stream data in Arc .

The following is an example 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(); } 
+2
source

All Articles