Best way to wait on two (or more) mpsc::Receivers?


#1

Hi all,

I know there is the unstable select!, but I want to use stable code. The best idea I have right now is to pass the thread to all senders, and have them run an unpark after sending, which if I use a buffered channel ought to enable the receiving thread to park after checking if anything is ready with try_recv.

Does this sound like a reasonable approach? Other ideas include:

  1. Another obvious approach would be to make a single channel with an enum type carrying the two kinds of information. I’d prefer to avoid that, since one of the two send channels is passed to a different crate (which shouldn’t know about the other channel).
  2. I could alternatively use the chan crate, but that requires every user of the sender crate to also use the chan crate, and I’d rather keep its API using the standard library.
  3. Another option would be to have its API accept a “sender” trait object (or a generic), which would enable me to write a sender that wraps the information in an enum. That would enable maximum flexibility in the API, but it would be nicer if the standard library defined said Sender trait, since otherwise every user of the library would need to define it… although I could at least define it for mpsc::Sender.

I’m sure there are other alternatives, but I’d love to hear what y’all would recommend as a workaround for select!.


#2

What problem are you trying to solve? It might be possible to expose an API that is channel agnostic.

(Hint: I had a similar desire as you. My answer was to write chan. :-))


#3

I’d use FnMut(T) -> SendError<T> for that purpose.


#4

From what I gather you don’t have control over the code of at least one of the senders.
You could create a thread (or multiple) that is a forwarding receiver; that just wraps what it receives and sends to the single destination receiver.


#5

I like @krdln’s suggestion, and am going to just accept a hook function that is FnOnce (since each sender will only need to send a single item). I think that should work (am implementing), and should be pretty efficient and flexible. Users of the crate can then use a simple closure to send the information via any sort of chan they care to, and can wrap it in any sort of Enum they might like.

I’m hoping to avoid creating helper threads beyond those that are truly needed, otherwise @jonh’s approach would work nicely.


#6

Somewhat off-topic, but, facing a similar problem, I’ve written the pipe-channel crate that wraps pipe(2), can be used with select(2), poll(2) and what have you, as well as integrated into event loops of all sorts.