DEV Community

Cover image for Random Rust Notes - 3
Nirmalya Sengupta
Nirmalya Sengupta

Posted on

Random Rust Notes - 3

[Cover image credit: https://pixabay.com/users/engin_akyurt-3656355]

This blog is a collection of notes of key learnings / understandings / Aha moments, as I am kayaking through demanding yet exciting waters, of Rust (#rustlang). If these help someone, I will be happy of course. OTOH, if someone happens to find defects in the code or gaps in my understanding, please correct me. I will remain thankful.

As a part of a personal project, I am in the middle of learning how to use channels to communicate between two threads. This is quite a common topic. Many people seem to have questions around this topic. Many answers / explanations are available.

These are my notes, though.

Takeaways from the previous note

The previous note is here (for a quick recap, in cases needed)

  • Using channels, multiple producers can send messages to a single consumer.
  • Each such producer must have its own copy of the sender-end of the channel. clone the sender-end for this.
  • Channels are unidirectional and FIFO in structure; therefore, every producer's messages to the consumer reach in the same order in which they are despatched.
  • Multiple producers messages may reach in any random order, though.

What is it that I am modeling (recap helps)

  • An in-memory dashboard, which
    • Works as a collector of events generated by a number of event-generators
    • Informs a viewer of the events as they are arriving and being collected
    • Dumpts a chronicle of the events that it receives before terminating
  • Each event generator is modeled as a thread that pushes the events and then terminates
  • An event inquirer - another thread itself - which registers itself with the dashboard, so that the dashboard can keep informing it of the events as they arrive

All communications between various threads, happen through channels and are based on an application-specific protocol, implemented as an Enumeration. Enumumerations help in ensuring that channels are bound to a particular type.

The dashboard is modeled as a struct. It has a lifecycle:

  • Created using a conventional new() function
  • Prepared with a ready() function
  • Nudged to receive, events from producers (separate threads, outside the struct) with a start() function
  • Brought to an end, by a stop() function

Having a lifecycle like this, helps in desigining and implementing, a clean, predictable and testable behaviour.

Key observations

  • The dashboard is built as a black-box like entity. It is created, used and destroyed using its APIs. Therefore, some other thread - may be the main thread - is expected to bring it forth and let it go, when done.
  • The dashboard doesn't know how many event producers are alive, at a given point in time. The receiving end is with the dashboard and the sending ends are with the event producers (remember, Sending ends need cloning). So, the dashboard waits till all the sending ends have gone out of existence ( dropped in Rust parlance), which is when the receiver in Dashboad, returns with an error. This is how the dashboard knows when not to expect any further events.
  • There are more than one channels, Obviously, distributing the sending and receiving ends has to be carefully and correctly done.
  • Receivers cannot be shared between threads, like the way Senders can be. Therefore, to share the receivers, one needs to wrap those in some kind mutually exclusive data structure and then shared. This mutual exclusion is important to ensure that one of the threads accesses it at a given point in time.

Top comments (0)