Trouble for "move" when I tried use multiple thread

I am new for rust and I get some move trouble when I want to use multiple thread to do something; and it seems I can’t "real" copy some data;

use std::collections::HashMap;
use std::sync::mpsc;
use std::thread;


pub fn frequency(input: &str, some_chars: Vec<char>){
    let all_chars = input.chars();
    let mut  unique_chars = vec![];
    for ci in all_chars {
        if ! unique_chars.contains(&ci) {
            unique_chars.push(ci);
        }
    }
    let (tx, rx) = mpsc::channel();

    for tci in some_chars {
        let tx_copy = tx.clone();
        thread::spawn(move || {
            let mut chars_count= 0 as usize;
            let all_chars_copy = all_chars.clone();
            for aci in all_chars_copy {
                if aci == tci {
                    chars_count += 1;
                }
            }
            tx_copy.send((tci, chars_count));
        });
    }

    for received in rx {
        println!("Got: {:?}", received);
    }

}


fn main() {
    let a_string = "dsfsdfdsfsdfsdfsdfsdfw4eer34fdefd";
    frequency(a_string, vec!['a', 'b', 'c']);
}

The compile error is as below; when I want to move some data on mutiple thread, i should copy some data to "move", but it seems look like failed; shall I get some advice for resolve this problem?

error[E0521]: borrowed data escapes outside of function
  --> src\main.rs:18:9
   |
6  |   pub fn frequency(input: &str, some_chars: Vec<char>){
   |                    -----  - let's call the lifetime of this reference `'1`
   |                    |
   |                    `input` is a reference that is only valid in the function body
...
18 | /         thread::spawn(move || {
19 | |             let mut chars_count= 0 as usize;
20 | |             let all_chars_copy = all_chars.clone();
21 | |             for aci in all_chars_copy {
...  |
26 | |             tx_copy.send((tci, chars_count));
27 | |         });
   | |          ^
   | |          |
   | |__________`input` escapes the function body here
   |            argument requires that `'1` must outlive `'static`

error[E0382]: use of moved value: `all_chars`

>Solution :

Your code has multiple issues:

  1. You already move all_chars before you even start the first thread here:
for ci in all_chars {

Since it’s cheap you can just create a new one like this:

for ci in input.chars() {
  1. Your’e trying to clone all_chars inside of the closure but at that point you already moved it, so either clone it outside:
        thread::spawn({
            let all_chars = all_chars.clone();
            move || {
                let mut chars_count = 0 as usize;
                for aci in all_chars {
                    if aci == tci {
                        chars_count += 1;
                    }
                }
                tx_copy.send((tci, chars_count));
            }
        });

or just create it from scratch again:

        thread::spawn(move || {
                let mut chars_count = 0 as usize;
                for aci in input.chars() {
                    if aci == tci {
                        chars_count += 1;
                    }
                }
                tx_copy.send((tci, chars_count));
            }
);
  1. You get bitten by the fact that you’re using .chars() borrows the original &str so it’s referencing local variables, to overcome that you can just use thread::scope because you read the contents of the threads at the end of the function anyways:
use std::collections::HashMap;
use std::sync::mpsc;
use std::thread;

pub fn frequency(input: &str, some_chars: Vec<char>) {
    let mut unique_chars = vec![];
    for ci in input.chars() {
        if !unique_chars.contains(&ci) {
            unique_chars.push(ci);
        }
    }
    let (tx, rx) = mpsc::channel();

    thread::scope(|s| {
        for tci in some_chars {
            let tx_copy = tx.clone();
            s.spawn(move || {
                let mut chars_count = 0 as usize;
                for aci in input.chars() {
                    if aci == tci {
                        chars_count += 1;
                    }
                }
                tx_copy.send((tci, chars_count));
            });
        }
    });

    for received in rx {
        println!("Got: {:?}", received);
    }
}
  1. Of course Masklinn is right you don’t need the channel at all.
use std::thread;

pub fn frequency(input: &str, some_chars: Vec<char>) {
    let mut unique_chars = vec![];
    for ci in input.chars() {
        if !unique_chars.contains(&ci) {
            unique_chars.push(ci);
        }
    }

    thread::scope(|s| {
        let mut ts = Vec::with_capacity(some_chars.len());
        for tci in some_chars {
            ts.push(s.spawn(move || {
                let mut chars_count = 0 as usize;
                for aci in input.chars() {
                    if aci == tci {
                        chars_count += 1;
                    }
                }
                (tci, chars_count)
            }));
        }
        for h in ts {
            let (tci, chars_count) = h.join().unwrap();
            println!("Got: {:?}", (tci, chars_count));
        }
    });
}

Leave a Reply