Rust: Почему указатель с Ve c > Плохо работает многопоточность по записи данных? - PullRequest
0 голосов
/ 07 мая 2020

Rust: Почему указатель с Ve c> плохо работает в многопоточности для записи данных?

Я хочу изменить big ve c в многопоточности параллельно.

отлично работает: u32

use std::thread;
use std::sync::Arc;

fn main() {
    let input = Arc::new([1u32, 2, 3, 4]);

    let mut handles = Vec::new();

    for t in 0..4 {
        let inp = input.clone();
        let handle = thread::spawn(move || unsafe {
            let p = (inp.as_ptr() as *mut u32).offset(t as isize);
            *p = inp[t] + t as u32 ;
        });

        handles.push(handle);
    }

    for h in handles {
        h.join().unwrap();
    }

    println!("{:?}", input);
}

плохо работает: Ve c>

Когда я меняю u32 на Ve c>, указатель работает плохо.

use std::thread;
use std::sync::Arc;
use std::collections::HashSet;

fn main() {

    let mut a = HashSet::new();
    a.insert("aaa");
    let input = Arc::new(vec![a.clone(), a.clone(), a.clone(), a.clone()]);

    let mut handles = Vec::new();

    for _t in 0..4 {
        let inp = input.clone();
        let handle = thread::spawn(move || unsafe {
            let p = (inp.as_ptr() as *mut Vec<HashSet<&str>>).offset(0);
            (*p)[0].insert("bbb");
        });

        handles.push(handle);
    }

    for h in handles {
        h.join().unwrap();
    }

    println!("{:?}", input);
}

Rust: Почему указатель с Ve c> плохо работает в многопоточности для записи данных?

Ответы [ 2 ]

0 голосов
/ 08 мая 2020

Трудно сказать, что не так с вашим исходным кодом, так как он выходит из строя на игровой площадке . Скорее всего, вы вызываете неопределенное поведение, беря ссылку на неизменяемый (!) Ve c и пытаясь изменить его элементы путем преобразования &Vec -> *mut Vec -> &mut Vec (при вызове метода). Множественные изменяемые ссылки на одно и то же - это большой запрет. Кроме того, ваш код даже использует один и тот же HashSet ((*p)[0]) параллельно параллельно, что, опять же, является неопределенным поведением.

Самый простой способ здесь - использовать потоки с областью видимости crossbeam. Они позволяют ссылаться на переменные стека, такие как ваш input. Vec также может выдавать отдельные изменяемые ссылки на свои элементы без использования unsafe. Используя это, ваш код, кажется, делает ожидаемую вещь.

use crossbeam::thread;
use std::collections::HashSet;

fn main() {
    let mut a = HashSet::new();
    a.insert("aaa");
    let mut input = vec![a.clone(), a.clone(), a.clone(), a.clone()];

    thread::scope(|s| {
        for set in &mut input {
            s.spawn(move |_| {
                set.insert("bbb");
            });
        }
    }).unwrap();

    println!("{:?}", input);
}
0 голосов
/ 08 мая 2020

Я нашел способ:

use std::thread;
use std::sync::Arc;
use std::collections::HashSet;

fn main() {
    let mut a = HashSet::new();
    a.insert("aaa");
    let input = Arc::new(vec![a.clone(), a.clone(), a.clone(), a.clone()]);

    let mut handles = Vec::new();

    for _t in 0..4 {
        let inp = input.clone();
        //let out = output.clone();
        let handle = thread::spawn(move || unsafe {
            let p = (inp.as_ptr() as *mut Vec<HashSet<&str>>).offset(0);

            (*p)[0].insert("bbb");
        });

        handles.push(handle);
    }


    for h in handles {
        h.join().unwrap();
    }

    println!("{:?}", input);
}

спасибо, ребята!

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