mnzl
mnzl

Reputation: 340

Get HashMap from thread

I am trying to get a value from a thread, in this case a HashMap. I reduced the code to the following (I originally tried to share a HashMap containig a Vec):

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

fn main() {
    let(tx, rx) = mpsc::channel();

    let n_handle= thread::spawn( || {
        tx.send(worker());
    });

    print!("{:?}", rx.recv().unwrap().into_inner().unwrap());
}


fn worker() -> Arc<Mutex<HashMap<String, i32>>>{
    let result: HashMap<String, i32> = HashMap::new();
    // some computation
    Arc::from(Mutex::from(result))
}

Still Rust says that:

std::sync::mpsc::Sender<std::sync::Arc<std::sync::Mutex<std::collections::HashMap<std::string::String, i32>>>> cannot be shared between threads safely

I read some confusing stuff about putting everything into Arc<Mutex<..>> which I also tried with the value:

let result: HashMap<String, Arc<Mutex<i32>>> = HashMap::new();

Can anyone point me to a document that explains the usage of the mpsc::channel with values such as HashMaps? I understand why it is not working, as the trait Sync is not implemented for the HashMap, which is required to share the stuff. Still I have no idea how to get it to work.

Upvotes: 0

Views: 1043

Answers (1)

Akiner Alkan
Akiner Alkan

Reputation: 6872

You can pass the values between threads with using mpsc channel.

Until you tag your thread::spawn with the move keyword like following:

thread::spawn(move || {});

Since you did not tag it with move keyword then it is not moving the outer variables into the thread scope but only sharing their references. Thus you need to implement Sync trait that every outer variable you use.

mpsc::Sender does not implement Sync that is why you get the error cannot be shared between threads.

The solution for your case would be ideal to move the sender to inside of the thread scope with move like following:

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

fn main() {
    let (tx, rx) = mpsc::channel();

    thread::spawn(move || {
        let _ = tx.send(worker());
    });

    let arc = rx.recv().unwrap();
    let hashmap_guard = arc.lock().unwrap();
    print!(
        "HashMap that retrieved from thread : {:?}",
        hashmap_guard.get("Hello").unwrap()
    );
}

fn worker() -> Arc<Mutex<HashMap<String, i32>>> {
    let mut result: HashMap<String, i32> = HashMap::new();
    result.insert("Hello".to_string(), 2);
    // some computation
    Arc::new(Mutex::new(result))
}

Playground

For further info: I'd recommend reading The Rust Programming Language, specifically the chapter on concurrency. In it, you are introduced to Arc: especially if you want to share your data in between threads.

Upvotes: 2

Related Questions