Я пытаюсь создать пул потоков, где каждый поток в пуле имеет тип thread_local!
, который может использоваться задачами в этом рабочем потоке.(T
в приведенном ниже примере).Основное назначение этого класса состоит в том, что ресурс T
не обязательно должен быть Send
, поскольку он будет создаваться локально в каждом рабочем потоке с помощью фабричного метода, который равен Send
.
Мой вариант использования - работа с пулом соединений !Send
db, но я попытался сделать его универсальным для типа ресурса T
.
extern crate threadpool;
use std::sync::mpsc::channel;
use std::sync::Arc;
// A RemoteResource is a threadpool that maintains a threadlocal ?Send resource
// on every pool in the thread, which tasks sent to the pool can reference.
// It can be used e.g., to manage a pool of database connections.
struct RemoteResource<T, M>
where
M: 'static + Send + Sync + Fn() -> T,
{
pool: threadpool::ThreadPool,
make_resource: Arc<M>,
}
impl<T, M> RemoteResource<T, M>
where
M: Send + Sync + Fn() -> T,
{
pub fn new(num_workers: usize, make_resource: M) -> Self {
RemoteResource {
pool: threadpool::ThreadPool::new(num_workers),
make_resource: Arc::new(make_resource),
}
}
pub fn call<F, R>(&mut self, f: F) -> R
where
R: 'static + Send,
F: 'static + ::std::marker::Send + FnOnce(&mut T) -> R,
{
let (tx, rx) = channel();
let maker = self.make_resource.clone();
self.pool.execute(move || {
use std::cell::RefCell;
thread_local!{
static UNSENDABLE_TYPE: RefCell<Option<T>> = RefCell::new(None)
}
UNSENDABLE_TYPE.with(|it| {
let mut mine = it.borrow_mut();
if mine.is_none() {
*mine = Some(maker());
}
if let Some(ref mut mine) = *mine {
let res = f(mine);
tx.send(res).unwrap();
return ();
}
unreachable!()
});
});
rx.recv().unwrap()
}
}
( Playground )
К сожалению, я не могу получить свой код для проверки типов, когда я абстрагируюсь над T
:
error[E0401]: can't use type parameters from outer function
--> src/lib.rs:38:56
|
17 | impl<T, M> RemoteResource<T, M>
| - type variable from outer function
...
28 | pub fn call<F, R>(&mut self, f: F) -> R
| ---- try adding a local type parameter in this method instead
...
38 | static UNSENDABLE_TYPE: RefCell<Option<T>> = RefCell::new(None)
| ^ use of type variable from outer function
Я попытался решить эту проблему, используя рекомендации из индекса ошибок компилятора Rust,но «копирование типа» не работает.Если «скопировать» T
в call
, то я получу ошибку «переменная затененного типа».Если я введу новый тип U
, то я снова получу очень запутанный E401, но на этот раз он предлагает добавить параметр типа к параметрам типа в call
, именно там, где я его уже добавил.Эта вторая вещь выглядит для меня как ошибка в компиляторе.(Если вам интересно об этом, вот детская площадка ).
Можно ли это проверить?Если нет, то почему?