пытается выполнить соединение потока в методе - PullRequest
0 голосов
/ 04 августа 2020

У меня есть этот код. Он запускает фоновый поток и передает ему работу. Я хочу иметь возможность дождаться полного закрытия фонового потока (я знаю, что в данный момент он не может остановиться, и я знаю, что он тоже должен быть в реализации Drop. Я просто пытаюсь получить базовый c кости идут)

use std::sync::mpsc;
use std::sync::mpsc::{Receiver, Sender};
use std::thread;
use std::thread::JoinHandle;

pub struct S2 {
    jh: JoinHandle<()>,
    tx: Sender<i32>,
}

impl S2 {
    pub fn new() -> S2 {
        let (tx, rx): (Sender<i32>, Receiver<i32>) = mpsc::channel();

        let jh = thread::spawn(move || loop {
            let item = rx.recv().unwrap();
            println!("got {:?}", item)
        });
        S2 { jh, tx }
    }

    pub fn queue(&self, item: i32) {
        self.tx.send(item).expect("oops");
    }

    pub fn wait(&mut self) {
        self.jh.join().expect("oops");
    }
}

fn main() {
    let s2 = S2::new();
    s2.queue(42);
    // s2.jh.join().expect("oops");
}

Закомментированная строка работает нормально. Но это открывает вызывающей стороне детали реализации. Я хочу это в методе. Но метод, который нельзя компилировать.

   Compiling tq3 v0.1.0 (C:\work\rust\tq3)
error[E0507]: cannot move out of `self.jh` which is behind a mutable reference
  --> src\main.rs:32:9
   |
32 |         self.jh.join().expect("oops");
   |         ^^^^^^^ move occurs because `self.jh` has type `std::thread::JoinHandle<()>`, which does not implement the `Copy` trait

Я пробовал свои обычные догадки, чтобы удовлетворить ржавчину, но пока не смог найти правильный.

1 Ответ

1 голос
/ 04 августа 2020

Функция wait, как вы ее определяете,

pub fn wait(&mut self) {
     self.jh.join().expect("oops");
}

принимает изменяемую ссылку на S2. Но JoinHandle::join потребляет дескриптор (он принимает не ссылку, а значение)

Ключ к пониманию того, как обойти ошибку, - это подумать о том, в каком состоянии будет находиться объект S2 после s2.wait().

Если вы хотите, чтобы объект оставался действительным, но содержащийся в нем дескриптор соединения больше не будет действительным, тогда тип дескриптора не может быть JoinHandle<()>, но может быть Option<JoinHandle<()>>.

Если объект больше не действует после вызова wait, вы можете сделать wait принять self вместо &mut self.

Вы можете увидеть примеры с обоими эти подходы здесь . Они действительно заслуживают лучшей обработки ошибок, особенно в случае S3, когда двойной вызов .wait() должен обрабатываться лучше. (В моей версии вы не можете выполнить двойной вызов S2, поскольку первый вызов потребляет ваш экземпляр).

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