1

我有一个从各种输入生成哈希的函数。我想存储一个这样的哈希,Arc<[u8; 16]>以便我可以在线程和结构之间共享它。之前,我将它存储为Vec<u8>,通过通道传递,然后将其转换为[u8; 16]本地。显然效率低下,因此Arc<[u8; 16]>. 但是当我进行转换时,我得到了这样的错误:

error[E0277]: `std::sync::mpsc::Sender<Header<'a, Body<'a>>>` cannot be shared between threads safely
   --> src/lib.rs:182:13
    |
182 |             spawn(move || {
    |             ^^^^^ `std::sync::mpsc::Sender<Header<'a, Body<'a>>>` cannot be shared between threads safely
    |
    = help: within `CreatorPipeline<Header<'a, Body<'a>>, std::sync::Arc<[u8; 16]>, (std::sync::Arc<[u8; 16]>, std::path::PathBuf, u64), (std::vec::Vec<u8>, u64, std::vec::Vec<u8>), Block, Body<'a>>`, the trait `std::marker::Sync` is not implemented for `std::sync::mpsc::Sender<Header<'a, Body<'a>>>`
    = note: required because it appears within the type `(std::sync::mpsc::Sender<Header<'a, Body<'a>>>, std::sync::mpsc::Receiver<Header<'a, Body<'a>>>)`
    = note: required because it appears within the type `CreatorPipeline<Header<'a, Body<'a>>, std::sync::Arc<[u8; 16]>, (std::sync::Arc<[u8; 16]>, std::path::PathBuf, u64), (std::vec::Vec<u8>, u64, std::vec::Vec<u8>), Block, Body<'a>>`
    = note: required because of the requirements on the impl of `std::marker::Send` for `&CreatorPipeline<Header<'a, Body<'a>>, std::sync::Arc<[u8; 16]>, (std::sync::Arc<[u8; 16]>, std::path::PathBuf, u64), (std::vec::Vec<u8>, u64, std::vec::Vec<u8>), Block, Body<'a>>`
    = note: required because it appears within the type `[closure@src/lib.rs:182:19: 232:14 file:std::path::PathBuf, self:&CreatorPipeline<Header<'a, Body<'a>>, std::sync::Arc<[u8; 16]>, (std::sync::Arc<[u8; 16]>, std::path::PathBuf, u64), (std::vec::Vec<u8>, u64, std::vec::Vec<u8>), Block, Body<'a>>, tx_main:std::sync::mpsc::Sender<std::sync::Arc<[u8; 16]>>, tx_input:std::sync::mpsc::Sender<(std::sync::Arc<[u8; 16]>, std::path::PathBuf, u64)>, tx_fd:std::sync::mpsc::Sender<(std::vec::Vec<u8>, u64, std::vec::Vec<u8>)>]`
    = note: required by `rayon_core::spawn::spawn`

还有11个这样的错误。的所有一些变化Foo cannot be shared between threads safely这是所有错误的要点。

这是我的代码片段:

...

// File creation pipeline
pub struct CreatorPipeline<A, B, C, D, E, F> {
    magic: Arc<[u8; 8]>,
    rec_set_id: Arc<RwLock<Option<&'static [u8; 16]>>>,
    writes: (Sender<A>, Receiver<A>),           // A: Header<Body>
    main: (Sender<B>, Receiver<B>),             // B: Arc<[u8; 16]>
    input: (Sender<C>, Receiver<C>),            // C: (Arc<[u8; 16]>, File)
    body: (Sender<F>, Receiver<F>),             // F: Body
    file_description: (Sender<D>, Receiver<D>), // D: (Arc<[u8; 16]>, u64, Vec<u8>)
    recovery: (Sender<E>, Receiver<E>),         // E: Block
}



// Creation pipeline methods
impl<'a>
    CreatorPipeline<
        Header<Body<'a>>,          // writes Packet
        Arc<[u8; 16]>,                 // main file_id
        (Arc<[u8; 16]>, PathBuf, u64), // input (file_id, file, length)
        (Vec<u8>, u64, Vec<u8>),       // file_description (name, length, hash_16k)
        Block,                         // recovery Block
        Body<'a>,                      // packet Body
    >
{
    ...

    // First Stage: Create file ids and partial bodies for FileDescription. Send
    // file ids, partial bodies and file readers to the correct channels.
    fn create_file_id(&self, files: Vec<PathBuf>) -> Result<(), ExitFailure> {
        let (tx_main, _) = &self.main; // sender for create_main()
        let (tx_input, _) = &self.input; // sender for create_input()
        let (tx_fd, _) = &self.file_description; // sender for create_fd()

        for file in files {
            let tx_main = tx_main.clone();
            let tx_input = tx_input.clone();
            let tx_fd = tx_fd.clone();

            // Spawn thread
            spawn(move || {
                let mut reader = File::open(&file)
                    .with_context(|_| format!("Could not open file {}", file.display()))
                    .unwrap();

                // Get filename from path
                let name = file
                    .file_stem()
                    .unwrap()
                    .to_string_lossy()
                    .into_owned()
                    .into_bytes();

                let length = {
                    let metadata = metadata(&file).unwrap();
                    metadata.len()
                };

                // Hash first 16k of the file
                let hash_16k = {
                    let mut hasher_16k = Md5::new();
                    let mut buffer = [0; 16384];
                    reader.read(&mut buffer).unwrap();
                    for byte in buffer.iter() {
                        hasher_16k.input([byte.clone()]);
                    }

                    let result = hasher_16k.result();
                    let hash_16k = result.as_slice().to_owned();
                    hash_16k
                };

                // Generate File ID
                let file_id = {
                    let mut hasher_file_id = Md5::new();
                    hasher_file_id.input(&hash_16k);
                    hasher_file_id.input(&length.to_le_bytes());
                    hasher_file_id.input(&name);
                    let file_id = hasher_file_id.result().to_vec();
                    let file_id = self.convert_to_byte_array(file_id);
                    Arc::new(file_id) // Problem line
                };

                // Partial FileDescription (name, length, hash_16k)
                let partial_body = (name, length, hash_16k);

                // sender for channels
                tx_main.send(Arc::clone(&file_id)).unwrap();
                tx_input.send((Arc::clone(&file_id), file, length)).unwrap();
                tx_fd.send(partial_body).unwrap();
            });
        }

        Ok(())
    }

    ...
}

这是完整的来源。
弧文档
人造丝文档

编辑:忘了提到我使用的是 2018 版稳定版。

4

1 回答 1

1

我从 Rust Discord 服务器获得了一些帮助。原来这let file_id = self.convert_to_byte_array(file_id);是问题所在。这是有道理的,我试图self进入多个线程,这显然是行不通的。我只是希望编译器错误更有帮助。

于 2019-04-29T18:00:03.470 回答