Search code examples
c#multithreadingsynchronized

making synchronized array that implements read\write methods


I have a class that has the fields: array of messages and current number of messages and the methods read\write.

When someone write, it puts the message into the array and increment current number of messages by one, and when someone trying to read it first decrease
current number of messages and then returns the last message.

I want to make this class to be Synchronized so it will allow to threads to write and read(when the array is empty i want that the thread will wait until will be something to read) from him and prevent data races.

I did this class that implements :

   class SynchronizedDATAStructure : DATAStructure
{
    private Mutex mutexR = new Mutex();
    private Mutex mutexW = new Mutex();
    private Semaphore semaphore = new Semaphore(0, int.MaxValue);
    private Semaphore semaphore2 = new Semaphore(1, 1);

    public override void Write(Message msg)
    {
        mutexW.WaitOne(); // allows only one thread each time to write
        semaphore2.WaitOne(); // checks if nobody is reading 
        base.Write(msg); // writing
        semaphore.Release(); // counts number of messages
        semaphore2.Release(); // finish to write
        mutexW.ReleaseMutex(); // finish the function
    }

    public override Message Read()
    {
        mutexR.WaitOne(); // allows only one thread each time to read
        semaphore.WaitOne();  // checks if there  are messages 
        semaphore2.WaitOne(); // checks if nobody is writing 
        Message msg1 = base.Read(); // reading
        semaphore2.Release(); // finish to read
        mutexR.ReleaseMutex(); // finish the function
        return msg1; // returns the messge
    }

When the threads start to write\read i got outOfBounds after while when thread trying to read from empty array.


Solution

  • You can make your code much simpler using Monitor:

    class SynchronizedDATAStructure : DATAStructure
    {
        private readonly object syncRoot = new object();
    
        public int MessageCount { get; private set; }
    
        public override void Write(Message msg)
        {
            lock (syncRoot)
            {
                base.Write(msg);
                MessageCount++;
    
                Monitor.Pulse(syncRoot);
            }
        }
    
        public override Message Read()
        {
            lock (syncRoot)
            {
                while (MessageCount <= 0)
                {
                    Monitor.Wait(syncRoot);
                }
    
                MessageCount--;
                return base.Read();
            }
        }
    }