0

I remember I saw a class with 2 exciting properties. I couldn't remember the class name but I think it was a collection, I'm not sure. The first property was named Read*word* and the second property was called Write*word*. Sadly I don't remember. Let me try to explain why these 2 properties exist. The idea was when a write happens we allow the already running "Reads" to finish but new ones will need to wait. See below how one would use this class.

var list = new ThreadSafeList();

// This is how we should read the collection.
using(var read = list.ReadLock)
{
 // If a write is happening we will wait until it finishes.
 await read.WaitAsync();

 // Do something with the list. If we are here in the execution no writing can happen, only reads.
}

// This is how we should change the collection.
using(var write = list.WriteLock)
{
 await write.WaitAsync();

 // Modify the collection, nobody reads it, so we are safe.
}

Do I remember right? Is there a collection that has similar properties? If not can somebody tell me how I should make a similar class is this an AutoResetEvent or a ManualResetEvent maybe a Sempahore? I don't know.

  • 1
    Probably related: [Is there anything like asynchronous BlockingCollection?](https://stackoverflow.com/questions/21225361/is-there-anything-like-asynchronous-blockingcollectiont) – Theodor Zoulias Sep 06 '22 at 07:54
  • Could you be thinking of [`ReaderWriterLockSlim`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.readerwriterlockslim?view=net-6.0) ? – Matthew Watson Sep 06 '22 at 08:39
  • Not exactly a list (which doesn't really make sense in a thread-safe context anyway) but if you need a MS solution you can use [`BufferBlock`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.tasks.dataflow.bufferblock-1) from the `System.Threading.Tasks.Dataflow` NuGet package. [Here](https://learn.microsoft.com/en-us/dotnet/standard/parallel-programming/how-to-write-messages-to-and-read-messages-from-a-dataflow-block#writing-and-reading-asynchronously) is an example for async usage. – György Kőszeg Sep 06 '22 at 10:16
  • `Channel` maybe? https://learn.microsoft.com/en-us/dotnet/api/system.threading.channels.channel-1?view=net-6.0 – Charlieface Sep 06 '22 at 11:09

1 Answers1

1

The idea was when a write happens we allow the already running "Reads" to finish but new ones will need to wait. See below how one would use this class.

Sounds like a reader/writer lock to me. Reader/writer locks can be used with collections, although the lock itself does not contain items.

There is a synchronous reader/writer lock in the BCL. There is no asynchronous version, though.

Usually, when people ask for a reader/writer lock, I ask them to carefully reflect whether they really need it. Just the fact that you have some code acting as a reader and other code acting as a writer does not imply you should have a reader/writer lock. RWLs are possibly one of the most misused synchronization primitives; a simple lock (or SemaphoreSlim for the asynchronous case) usually suffices just fine.

Is there a collection that has similar properties?

There are certainly reader/writer collections available. These work by containing a number of items and permit different parts of code to produce or consume items. Hence the common name "producer/consumer" collections.

The one I would recommend these days is System.Threading.Channels. TPL Dataflow is another option.

Note that you don't have to take any locks with Channels/Dataflow. Your producers just produce data items, and your consumers just consume them. All the locking is internal to these collections.

If not can somebody tell me how I should make a similar class

If, after careful reflection, you really do want an asynchronous reader/writer lock, you can make one like this.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810