Не удается разыменовать MutexGuard, потому что vec не реализует свойство копирования

#multithreading #rust

Вопрос:

Новичок в ржавчине. Пытаюсь передать право собственности на a Vec<Option<Box<dyn CoolTrait>>> в потоке, но я не могу разыменовать MutexGuard:

 fn main() {
    let cool_vec: Vec<Option<Box<dyn CoolTrait>>> = vec![];
    let vec_mx = Mutex::new(cool_vec);

    let mythread = thread::spawn(move || {
        let mxguard = vec_mx.lock().unwrap();
        do_an_action(*mxguard);
    });
}
 

Компилятор жалуется на эту последнюю строку с:

 cannot move out of dereference of MutexGuard<'_, Vec<Option<Box<dyn CoolTrait>>>
move occurs because value has type Vec<Option<Box<dyn CoolTrait>>>, which does not implement the Copy trait
 

Есть ли какой-нибудь способ сделать это?

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

1. Пытаясь передать право собственности на a Vec<_> в потоке , вы уже передали право собственности потоку, есть ли какая-либо другая причина для разыменования MutexGuard ? Или вы хотите иметь что-то подобное ?

2. @herpderp расскажите нам, чего вы хотите достичь, а не как вы планируете это сделать

3. В принципе, основной поток должен владеть vec, как и функция do_an_action в другом потоке. Я пытаюсь передавать его туда и обратно между потоками

4. Обратите внимание, что голый Mutex почти всегда бесполезен, так как у него может быть только один владелец, поэтому нет необходимости в блокировке. Mutex имеет смысл только в том случае, если он стоит за какой-то ссылкой, например amp;Mutex (что почти наверняка должно быть 'static ) или Arc<Mutex> .

5. @herpderp, который не может работать, Mutex может только раздавать (изменяемые) ссылки. Чтобы получить Vec значение, вам нужно будет mem::take указать значение, переместить его в функцию… тогда main оно окажется пустым Vec , что было бы не очень полезно. По определению, у вас не может быть как потока, так и main собственного одного и того же вектора, вам нужен общий владелец (an Arc ), чтобы фактически владеть вещью и обеспечивать доступ (но не передавать право собственности).

Ответ №1:

Из комментария:

Я пытаюсь передать [вектор] туда и обратно между потоками

Чтобы отправить значение потоку, вам не нужно Mutex , вы можете просто переместить значение в закрытие, которое будет выполняться потоком:

 trait CoolTrait: Send {}

fn main() {
    let cool_vec: Vec<Option<Box<dyn CoolTrait>>> = vec![];
    let mythread = thread::spawn(move || {
        do_an_action(amp;cool_vec);
    });
    // do other things...
    mythread.join().unwrap();
}
 

Игровая площадка

Обратите внимание, что CoolTrait Send для передачи объектов признаков между потоками необходимо использовать в качестве супер-признака (или его dyn CoolTrait необходимо изменить dyn CoolTrait Send ).

Чтобы отправить объект обратно в основной поток после mythread завершения, вы можете использовать возвращаемое значение закрытия, переданное thread::spawn() :

 fn main() {
    let cool_vec: Vec<Option<Box<dyn CoolTrait>>> = vec![];
    let mythread = thread::spawn(move || {
        do_an_action(amp;cool_vec);
        cool_vec
    });
    // cool_vec is now owned by mythread, do other things here
    // ...
    let cool_vec = mythread.join().unwrap();
    // mythread is done and we got cool_vec back!
    // ...
}
 

Для обмена значениями между потоками, не дожидаясь завершения потока, можно использовать каналы.