满足条件时终止线程

Terminating threads when a condition is met

我想高效地搜索两个 HashMap 的键以获取单个值,并在找到该值后终止两个线程。我目前正在使用两个单独的消息通道(即两个发射器和两个接收器)来执行此操作,但我不确定这是正确的方法。鉴于 mpsc::channel 的“mpsc”组件代表“多个生产者,单个消费者”,因此拥有多个生产者和多个消费者感觉不对。那么,有没有更好的方法同时搜索两个数组呢?

我的代码Also available in the playground:

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

I'm trying to search for a key that could exist in two different hash maps. In this example, I'm searching for 11 in both sets of keys, and want to terminate both threads when I've found it in either one of the sets of keys.

在这种情况下,没有理由使用 mpsc 来传达停止条件。您可以使用简单的原子布尔值:

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() 没有意义。除了减慢应用程序速度外,它没有任何作用