Rust: сбой соединения с потоком: не удается выйти из разыменования `std:: sync:: MutexGuard`

#rust

#Ржавчина

Вопрос:

Мне трудно понять, как решить эту проблему.

Итак, у меня есть класс ArcWorker , содержащий общую ссылку на Worker (как вы можете заметить ниже).

Я написал функцию в ArcWorker вызываемой join() , в которой строка self.internal.lock().unwrap().join(); завершается ошибкой со следующей ошибкой:

не удается выйти из разыменования std::sync::MutexGuard<'_, models::worker::Worker>

Что я пытаюсь через эту строку, так это заблокировать мьютекс, развернуть и вызвать join() функцию из рабочего класса.

Насколько я понимаю, как только вызывается функция блокировки и она заимствует ссылку на self (amp;self), мне нужен какой-то способ передать self по значению в join (функция объединения std::thread требует передачи self по значению).

Что я могу сделать, чтобы это сработало? Пытался найти ответ на мой вопрос в течение нескольких часов, но безрезультатно.

 pub struct Worker {
  accounts: Vec<Arc<Mutex<Account>>>,
  thread_join_handle: Option<thread::JoinHandle<()>>
}

pub struct ArcWorker {
  internal: Arc<Mutex<Worker>>
}

impl ArcWorker {
  pub fn new(accounts: Vec<Arc<Mutex<Account>>>) -> ArcWorker {
    return ArcWorker {
      internal: Arc::new(Mutex::new(Worker {
        accounts: accounts,
        thread_join_handle: None
      }))
    }
  }

  pub fn spawn(amp;self) {
    let local_self_1 = self.internal.clone();
    
    self.internal.lock().unwrap().thread_join_handle = Some(thread::spawn(move || {
      println!("Spawn worker");
      local_self_1.lock().unwrap().perform_random_transactions();
    }));
  }

  pub fn join(amp;self) {
    self.internal.lock().unwrap().join();
  }
}

impl Worker {
  fn join(self) {
    if let Some(thread_join_handle) = self.thread_join_handle {
      thread_join_handle.join().expect("Couldn't join the associated threads.")
    }
  }

  fn perform_random_transactions(amp;self) {
    
  }
}
 

Комментарии:

1. Поскольку вы уже JoinHandle используете an Option , вы можете сделать Worker::join() take amp;mut self вместо self и изменить if let на if let Some(thread_join_handle) = self.thread_join_handle.take() (обратите внимание на добавленное take() ). Затем ArcWorker::join() следует скомпилировать как есть.

2. Потрясающе, это было то, что мне нужно. Теперь это работает. Большое спасибо!

Ответ №1:

Поскольку у вас уже есть JoinHandle опция, вы можете сделать Worker::join() take amp;mut self вместо self и изменить if let условие на:

 // note added `.take()`
if let Some(thread_join_handle) = self.thread_join_handle.take() {
 

Option::take() переместит дескриптор из опции и предоставит вам право собственности на нее, оставив None при self.thread_join_handle этом . С этим изменением ArcWorker::join() следует скомпилировать как есть.