首页 > 解决方案 > 满足条件时终止线程

问题描述

我想有效地在两个 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,并希望在我在任一组键中找到它时终止两个线程。

标签: multithreadingrustconcurrency

解决方案


我正在尝试搜索可能存在于两个不同哈希映射中的键。在此示例中,我在两组键中搜索 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()在循环中做是没有意义的。除了减慢应用程序的速度之外,它没有实现任何目标

推荐阅读