Decent way to drop orginal sender after multiple clones in for_each

#1

Hi, I clone several senders in a for_each loop. I mainly use those clones to send messages, but I found after that I have to use the original one send at least one message otherwise the rx got stuck… my workaround is like this:

        let (tx, rx) = channel();

        (0..core_num).for_each(|i| {
            let tx_clone = Sender::clone(&tx);

           spawn(move || { //do stuff with tx_clone; })
        });

        //use the origin at least once here... just send nothing
        spawn(move || {
            tx.send(None).unwrap();
        });

       //otherwise, rx will get stuck
       rx.iter()....

Is there any decent way to release the original tx? Thank you in advance.

#2

drop(tx) will drop the sender held by the parent thread.

Or you could add the move keyword to your outer closure, so that it consumes tx by value. Then it’ll be dropped when for_each returns.

#3

Hi, thanks for the reply, but I’ve tried the drop(tx), didn’t release the rx block…

#4

Can you share the code that isn’t working?

Here’s a working version using drop: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=723624ab48ea1eba33cf6d4f8a362d40

use std::sync::mpsc::{channel, Sender};
use std::thread::spawn;

fn main() {
        let core_num = 4;
        let (tx, rx) = channel();

        (0..core_num).for_each(|i| {
            let tx_clone = Sender::clone(&tx);

           spawn(move || { tx_clone.send(Some(i)).unwrap(); });
        });
        
        drop(tx);

       //otherwise, rx will get stuck
       for i in rx.iter() {
           println!("{:?}", i);
       }
}
#5

Ah, I found I made a mistake on this… I tried the drop on a slow code, so it didn’t return for few seconds. So I just thought it didn’t work and terminated… After waiting for few seconds, it works… Thank you very much for your time, and sorry for my mistake…

1 Like