The documentation for Channel.CreateUnbounded says:
Creates an unbounded channel usable by any number of readers and writers concurrently.
However Channel has properties for a single ChannelReader
and ChannelWriter
only, and there doesn't appear to be a way to create a reader/writer explicitly around an existing channel.
I had thought that if you had multiple producers/consumers they should share the same instance of a writer/reader, is this incorrect? Is the "number of readers/writers" talking about concurrent access rather than number of class instances?
Yes, the documentation means multiple producers (writers) and consumers (readers). All producers are allowed to use the single ChannelWriter
of the channel, and all consumers are allowed to use its single ChannelReader
. No external synchronization is required. The Channel<T>
class is 100% thread-safe.
To be clear, the above is about a Channel<T>
instantiated with the default options. It is possible to create intentionally a non-thread-safe unbounded channel by configuring it with the SingleReader
option:
Channel<T> channel = Channel.CreateUnbounded<T>(new UnboundedChannelOptions()
{
SingleReader = true
});
With this configuration you get a channel that is presumably faster than the default, but it does not work correctly when used by multiple consumers. Technically you get a Channel<T>
implementation that instead of being backed by a ConcurrentQueue<T>
, it is backed by the internal collection SingleProducerSingleConsumerQueue<T>
.
There is also a SingleWriter
option, which is currently (.NET 9) purely decorative. Setting this option has no effect on the Channel<T>
implementation that you get (source code).
Important: In case of multiple consumers, each item passed through the channel will be received by only one consumer. The Channel<T>
doesn't support propagating one element to multiple consumers, like it does the BroadcastBlock<T>
dataflow block for example.