Rust: как передать hashmap между thread?
Только начал работать с тредами в Rust. Не могу передать хэштаблицу между двумя тредами. Как правильно это делать и где моя ошибка ? Задача - собирать хэштаблицу в одном треде и печатать в другом.
use std::thread;
use std::time::Duration;
use std::fs;
use std::io::{stdin, Read};
use std::collections::HashMap;
fn main() {
let mut hello = String::from("Hello, ");
let mut influx_data:HashMap<String, i32> = HashMap::new();
//second thread
thread::spawn(move || {
let mut character = [0];
hello = String::from("sasasas ");
while let Ok(_) = stdin().read(&mut character) {
if character[0] == b'\n' {
influx_data.entry(hello).and_modify(|count| *count += 1).or_insert(1);
println!("counter_bss cnt=7\n");
}
}
thread::sleep(Duration::from_secs(1));
});
//main thread
loop {
let data = "Some data!";
fs::write("/tmp/foo", data).expect("Unable to write file");
for (key, value) in &influx_data {
println!("{} {}", key, value);
}
thread::sleep(Duration::from_secs(10));
}
}
Ошибка
|
23 | influx_data.entry(hello).and_modify(|count| *count += 1).or_insert(1);
| ^^^^^ value moved here, in previous iteration of loop
Ответы (1 шт):
Перво-наперво, у вас проблема не с мапой, а с ключом hello
. Rust беспокоится, что символ \n
может встретиться несколько раз, а entry
дропнет ключ после первого раза. Вам нужно вызывать entry(hello.clone())
Далее, у вас один объект HashMap, но писатели и читатели находятся в разных потоках. У них разное время жизни, не вложенное друг в друга. Поэтому вы не можете сделать просто ссылку и передать её в функцию spawn, получите ошибку
`influx_data` does not live long enough
borrowed value does not live long enough
Вам нужно сделать shared container. Специально для многопоточного доступа в Rust есть Mutex
и Arc
. Комбинация этих контейнеров даёт общий доступ к объектам из разных потоков
let data_owner = Arc::new(Mutex::new(influx_data));
let data_for_thread = data_owner.clone();
Контейнер data_owner
хранит вашу мапу для main
, контейнер data_for_thread
переедет в замыкание. Для доступа к мапе нужно захватывать мутекс:
data_for_thread.lock().unwrap().entry(...)
...
for (key, value) in data_owner.lock().unwrap().iter() {...}
use std::collections::HashMap;
use std::fs;
use std::io::{stdin, Read};
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;
fn main() {
let mut hello = String::from("Hello, ");
let influx_data: HashMap<String, i32> = HashMap::new();
let data_owner = Arc::new(Mutex::new(influx_data));
let data_for_thread = data_owner.clone();
//second thread
thread::spawn(move || {
let mut character = [0];
hello = String::from("sasasas ");
while let Ok(_) = stdin().read(&mut character) {
if character[0] == b'\n' {
data_for_thread
.lock()
.unwrap()
.entry(hello.clone())
.and_modify(|count| *count += 1)
.or_insert(1);
println!("counter_bss cnt=7\n");
}
}
thread::sleep(Duration::from_secs(1));
});
//main thread
loop {
let data = "Some data!";
fs::write("/tmp/foo", data).expect("Unable to write file");
for (key, value) in data_owner.lock().unwrap().iter() {
println!("{} {}", key, value);
}
thread::sleep(Duration::from_secs(10));
}
}
Лог получается такой:
1
counter_bss cnt=7
2
counter_bss cnt=7
3
counter_bss cnt=7
sasasas 3
4
counter_bss cnt=7
sasasas 4
5
counter_bss cnt=7
sasasas 5
Работает