multithreading - 满足条件时终止线程
问题描述
我想有效地在两个 HashMap 的键中搜索单个值,并在找到该值后终止两个线程。我目前正在使用两个单独的消息通道(即两个发送器和两个接收器)来执行此操作,但我不确定这是正确的方法。鉴于“mpsc”组件mpsc::channel
代表“多个生产者,单个消费者”,拥有多个生产者和多个消费者感觉是错误的。那么,有没有更好的方法来同时搜索两个数组呢?
我的代码也可以在操场上找到:
use std::collections::HashMap;
use std::array::IntoIter;
use std::thread;
use std::time::Duration;
use std::iter::FromIterator;
use std::sync::mpsc;
fn main() {
let m1 = HashMap::<_, _>::from_iter(IntoIter::new([(1, 2), (3, 4), (5, 6), (7,8), (9, 10)]));
let m2 = HashMap::<_, _>::from_iter(IntoIter::new([(1, 2), (3, 4), (5, 6), (7,8), (9, 10), (11, 12), (13, 14), (15, 16), (17,18), (19, 20)]));
let (tx1, rx1) = mpsc::channel::<u8>();
let (tx2, rx2) = mpsc::channel::<u8>();
let handle1 = thread::spawn(move || {
let iter_keys1 = m1.keys();
for k in iter_keys1 {
if k.clone() == 11u8 {
tx2.send(*k);
break
} else {
println!("Key from handle1: {}", k);
}
thread::sleep(Duration::from_millis(1));
}
for received in rx1 {
let into: u8 = received;
if into == 11u8 {
println!("handle2 sent a message to receiver1: {}", into);
break
}
}
m1
});
let handle2 = thread::spawn(move || {
let iter_keys2 = m2.keys();
for k in iter_keys2 {
if k.clone() == 11u8 {
tx1.send(*k);
break
} else {
println!("Key from handle2: {}", k);
}
thread::sleep(Duration::from_millis(1));
}
for received in rx2 {
let into: u8 = received;
if into == 11u8 {
println!("handle1 sent a message to receiver2: {}", into);
break
}
}
m2
});
handle1.join().unwrap();
handle2.join().unwrap();
}
一些相关的问题:是否有实际理由使用sleep
,或者这是否只是为了更容易查看小样本的并发处理结果?当我注释掉这些thread::sleep(Duration::from_millis(1));
行时,似乎线程正在按顺序处理:
Key from handle1: 9
Key from handle1: 5
Key from handle1: 3
Key from handle1: 1
Key from handle1: 7
Key from handle2: 1
handle2 sent a message to receiver1: 11
澄清:
我正在尝试搜索可能存在于两个不同哈希映射中的键。在此示例中,我在两组键中搜索 11,并希望在我在任一组键中找到它时终止两个线程。
解决方案
我正在尝试搜索可能存在于两个不同哈希映射中的键。在此示例中,我在两组键中搜索 11,并希望在我在任一组键中找到它时终止两个线程。
在这种情况下,没有理由使用mpsc
来传达停止条件。您可以使用简单的原子 bool:
use std::array::IntoIter;
use std::collections::HashMap;
use std::iter::FromIterator;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::thread;
fn main() {
let m1 = HashMap::<_, _>::from_iter(IntoIter::new([(1, 2), (3, 4), (5, 6), (7, 8), (9, 10)]));
let m2 = HashMap::<_, _>::from_iter(IntoIter::new([
(1, 2),
(3, 4),
(5, 6),
(7, 8),
(9, 10),
(11, 12),
(13, 14),
(15, 16),
(17, 18),
(19, 20),
]));
let stop_signal = Arc::new(AtomicBool::new(false));
let stop = stop_signal.clone();
let h1 = thread::spawn(move || {
let keys = m1.keys();
for &k in keys {
if stop.load(Ordering::Relaxed) {
println!("Another thread found it!");
break;
}
if k == 11u8 {
stop.store(true, Ordering::Relaxed);
// do something with the found key
println!("Found by thread 1");
break;
}
}
m1
});
let stop = stop_signal.clone();
let h2 = thread::spawn(move || {
let keys = m2.keys();
for &k in keys {
if stop.load(Ordering::Relaxed) {
println!("Another thread found it!");
break;
}
if k == 11u8 {
stop.store(true, Ordering::Relaxed);
// do something with the found key
println!("Found by thread 2");
break;
}
}
m2
});
h1.join().unwrap();
h2.join().unwrap();
}
您的原始代码有几个问题:
- 其中一个线程即使在它完成映射后也会一直保持活动状态,直到它收到一条消息。
- 即使其中一个线程找到了密钥,另一个线程仍然会继续搜索它
thread::sleep()
在循环中做是没有意义的。除了减慢应用程序的速度之外,它没有实现任何目标
推荐阅读
- database - Passing Dependent Selection Values in Laravel
- haskell - 常量的模式匹配
- laravel - laravel : get properti from function in same class and parsing to view
- excel - error while connecting to oracle db using oracle client. I am able to connect using ODBC data source administrator. But not in Excel VBA
- firebase - 无法再部署到 Firebase - “规则太多”
- jenkins - Conditional SVN checkout in Jenkins
- oracle - Restore oracle 9i db with dbf only (after shutdown abort)
- sql - How to fix "current transaction is aborted commands ignored"
- python - 计算代码中的时间复杂度 - 嵌套循环
- sql - 用于更新内容的 DELETE 方法 - 可以吗?