using System;
using System.Threading;
using System.Collections.Generic;
using System.Text;

namespace ReadWriteLockDemo
{
   class Program
   {
      // w tym wypadku współdzielonym zasobem jest po prostu zmienna typu int
      static int sharedResource = 42;
      static int numTimeouts = 0;
      static ReaderWriterLock rwl = new ReaderWriterLock();

      static void Main(string[] args)
      {
         // tworzymy 10 wątków ubiegających się o dostęp w trybie do zapisu
         Thread[] writers = new Thread[10];
         for (int i = 0; i < 10; i++)
         {
            Thread writeThread = new Thread(new ThreadStart(DoWrite));
            writers[i] = writeThread;
            writers[i].Start();
         }

         // tworzymy 40 wątków ubiegających się o dostęp w trybie do odczytu
         Thread[] readers = new Thread[40];
         for (int j = 0; j < 40; j++)
         {
            Thread readThread = new Thread(new ThreadStart(DoRead));
            readers[j] = readThread;
            readers[j].Start();
         }

         // oczekujemy, aż wszystkie wątki zakończą pracę
         foreach (Thread writer in writers)
            writer.Join();
         foreach (Thread reader in readers)
            reader.Join();

         Console.WriteLine("Praca zakończona, wystąpiły zaledwie {0} przerwy.", numTimeouts);
         Console.ReadLine();
      }

      static void DoWrite()
      {
         try
         {
            rwl.AcquireWriterLock(100);
            try
            {
               Interlocked.Increment(ref sharedResource);
               Thread.Sleep(15);
            }
            finally
            {
               rwl.ReleaseWriterLock();
            }
         }
         catch (ApplicationException ae)
         {
            Interlocked.Increment(ref numTimeouts);
         }
      }

      static void DoRead()
      {
         try
         {
            rwl.AcquireReaderLock(100);
            try
            {
               Console.WriteLine("Badanie wartości zmiennej współdzielonej: {0}",
               sharedResource);
            }
            finally
            {
               rwl.ReleaseReaderLock();
            }
         }
         catch (ApplicationException ae)
         {
            Interlocked.Increment(ref numTimeouts);
         }
      }
   }
}
