【问题标题】:Hanging in channel receiver iterator in Rust?挂在Rust中的通道接收器迭代器中?
【发布时间】:2021-06-02 19:05:04
【问题描述】:

以下代码挂在迭代器中:(playground)

#![allow(unused)]
fn main() {
    use std::sync::mpsc::channel;
    use std::thread;
    
    let (send, recv) = channel();
    let num_threads = 3;
    for i in 0..num_threads {
        let thread_send = send.clone();
        thread::spawn(move || {
            loop { // exit condition does not matter, breaking right after the 1st iteration
                &thread_send.send(i).unwrap(); // have to borrow in the loop
                break;
            }
            println!("thread {:?} finished", i);
        });
    }

    // drop `send` needed here (as it's cloned by all producers)?
    
    for x in recv { // hanging
        println!("Got: {}", x);
    }
    println!("finished iterating");
}

在输出中我们可以清楚地看到退出的线程(因此线程本地克隆的发送者被丢弃):

thread 0 finished
Got: 0
Got: 1
Got: 2
thread 1 finished
thread 2 finished

finished iterating 永远不会被打印,并且该过程在操场上被中断(在本地永远挂起)。

什么原因?

PS。需要在线程中循环(这是实际使用的代码的简化示例)以显示真实用例。

【问题讨论】:

  • 你已经想通了。您需要将send 放在指定的位置,因为只有在最后一个发件人被丢弃时通道才会关闭。并且主线程的发送只有在超出函数结束的范围时才会被丢弃。
  • @HHK 我尝试调用send.drop(),但编译器不允许这样做。感谢您确认我正朝着正确的方向前进(请转换为答案以接受它)。
  • 它是drop(send)(正如send.drop() 的错误消息指出的那样)。
  • 我强烈建议你更喜欢使用范围,play.rust-lang.org/…(例如使用函数)

标签: multithreading rust concurrency channel


【解决方案1】:

您需要将send 放在您的评论指示的位置,因为该频道仅在最后一个发件人被丢弃时关闭。主线程的发送只有在超出函数末尾的范围时才会被丢弃。

正如 Stargateur 在 cmets (playground) 中指出的那样,您可以显式调用 drop(send) 或重组代码,以便在开始我们的接收循环之前主线程的发送超出范围。这是可取的,因为读者可以立即清楚send 被删除的位置,而drop(send) 语句很容易被遗漏。

【讨论】:

    猜你喜欢
    • 2021-04-14
    • 1970-01-01
    • 2020-11-20
    • 2023-03-31
    • 2023-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多