Невозможно использовать переменные Ar c при порождении потоков - PullRequest
0 голосов
/ 11 апреля 2020

У меня есть следующая структура для представления объекта сервера:

pub struct Server {
    client_managers: Arc<ClientManager>,
    listener: Option<TcpListener>,
}

Вот код, который получает соединение клиента и обрабатывает его в новом потоке:

fn serve(&self) {
    for stream in self.listener.as_ref().unwrap().incoming() {
        match stream {
            Ok(stream) => {
                let client_manager = &mut self.client_managers.clone();
                // let client_manager = Arc.new(self.client_managers);
                thread::spawn(move || {
                    client_manager.do_something();

                });
            }
            Err(e) => {
                println!("connection error: {}", e);
            }
        }
    }
}

Однако , Я получаю следующую ошибку при компиляции:

error[E0716]: temporary value dropped while borrowed
  --> server/src/server.rs:37:47
   |
37 |                       let client_manager = &mut self.client_managers.clone();
   |                                                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
38 |                       // let client_manager = Arc.new(self.client_managers);
39 | /                     thread::spawn(move || {
40 | |                         client_manager.nothing();
41 | |                     });
   | |______________________- argument requires that borrow lasts for `'static`
42 |                   }
   |                   - temporary value is freed at the end of this statement

Я понял, почему эта ошибка произошла. Мой вопрос:

1) Я использую Ar c, следуя некоторым учебникам в Интернете. ( Пример ) Но почему их примеры работают, а не мои?

2) Как я могу исправить эту ошибку в моей ситуации? (Я все еще хочу поделиться объектом client_manager).

1 Ответ

2 голосов
/ 12 апреля 2020

thread::spawn принимает закрытие, равное 'static, что означает, что он не может заимствовать данные извне потока. Тем не менее, эта строка будет клонировать Arc и заимствовать его, и передать заимствованную ссылку в поток:

let client_manager = &mut self.client_managers.clone();
thread::spawn(move || {
    client_manager.do_something();
//  ^-- client_manager is a `&mut Arc<_>` borrowed from outside the thread
});

Вместо этого вам нужно просто клонировать Arc, а не заимствовать его в перед его передачей в поток:

let client_manager = self.client_managers.clone();
thread::spawn(move || {
    client_manager.do_something();
//  ^-- client_manager is a `Arc<_>` owned by the new thread
});

Arc имеет общее владение значением, поэтому оно уничтожается только после того, как все указатели Arc, ссылающиеся на него, выпадают из области видимости, даже если нити.

...