Как отложить проверку времени жизни до времени выполнения - PullRequest
0 голосов
/ 04 ноября 2019

Я пытаюсь передать нестатическое замыкание в Токио. Очевидно, это не работает. Есть ли способ убедиться, что время жизни соответствует времени выполнения? Вот что я попробовал:

Попытка с помощью Arc

Чтобы не передавать замыкание непосредственно в Tokio, я поместил его в структуру, которая управляет нашими таймерами:

type Delays<'l, K: Eq + Hash + Debug + Copy + Send> = HashMap<K, Box<dyn FnOnce() + 'l + Send>>;

pub struct Timers<'l, K: Eq + Hash + Debug + Clone + Send> {
    delays: Arc<Mutex<Delays<'l, K>>>,
}

impl для этой структуры позволяет нам легко добавлять и удалять таймеры. Мой план состоял в том, чтобы каким-то образом передать статическое замыкание в tokio, просто переместив ссылку Weak на мэш-таблицу с мьютексами:

// remember handler function
        delays.insert(key.clone(), Box::new(func));

        // create a weak reference to the delay map to pass into the closure
        let weak_handlers = Arc::downgrade(&self.delays);

        // task that runs after a delay
        let task = Delay::new(Instant::now() + delay)
            .map_err(|e| warn!("Tokio timer error: {}", e)) // Map the error type to ()
            .and_then(move |_| {
                // get the handler from the table, of which we have only a weak ref.
                let handler = Weak::upgrade(&weak_handlers)
                    .ok_or(())? // If the Arc dropped, return an error and thus aborting the future
                    .lock()
                    .remove(&key)
                    .ok_or(())?; // If the handler isn't there anymore, we can abort aswell.

                // call the handler
                handler();

                Ok(())
            });

Так что с помощью Weak мы гарантируем, что прервемся, если хештаблица была удалена.

Важно знать, что время жизни 'l такое же, как и у структуры Timers, но как я могу сказать компилятору? Кроме того, я думаю, что реальная проблема в том, что Weak<T>: 'static не удовлетворен.

Пишу это сам, используя unsafe

Я пытался создать что-то похожее на Sc , чтобы достичьэто. Во-первых, Sc собирается работать здесь? Я читаю код и понимаю его. Я не вижу никаких очевидных проблем - хотя было довольно сложно прийти к выводу, что метод map на самом деле безопасен, потому что ссылка обязательно будет отброшена в конце map и не будет где-то сохранена.

Поэтому я попытался адаптировать Sc для своих нужд. Это всего лишь грубый набросок, и я знаю, что с этим есть некоторые проблемы, но я считаю, что что-то вроде этого должно быть возможным:

  • Иметь struct Doa<T>, которому будет принадлежать T
  • Doa::ref(&self) -> DoaRef<T> создаст непрозрачный объект, который внутри содержит *const u8 для принадлежащего объекта.
    • DoaRef не содержит ссылок с нестатическими временами жизни и, следовательно, можетбыть переданным tokio.
  • Иметь impl<T> Drop for Doa<T>, который устанавливает *const u8 на null
  • Так что DoaRef теперь может проверить, существует ли значение до сих пори получить ссылку на него.

Я также пытался убедиться, что время жизни &self в ref должно быть больше, чем время жизни ссылок в T, чтобы убедиться, что это работаеттолько если Doa действительно живет дольше, чем объект, на который указывает указатель.

struct Doa<'t, T: 'l> { ... }
pub fn ref(&'s self) -> DoaRef<T> where 't: 'a

Но тогда T ограничен на протяжении жизни и, поскольку DoaRef параметризован, DoaRef: 'static не выполняетсябольше.

Или есть какой-то ящик, или, может быть, даже что-то в std тшляпа может это сделать?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...