// // Author: Carson Jones // Adapted from "Art of Multiprocessor Programming" by Herlihy and Shavit // CS6966 // using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using ReadWriteLock; using Microsoft.VisualStudio.TestTools.UnitTesting; namespace TestFifoReadWriteLock { public class ReadWriteRunner { FifoReadWriteLock rwlock = new FifoReadWriteLock(); ILock writeLock; ILock readLock; List readers; List writers; int rwdata = 0; int itemsWritten = 0; int itemsToWrite = 0; bool stillrun = true; bool readerlocked = false; bool writerlocked = false; Object dataavailable = new Object(); Object internalReadLock = new Object(); Object internalWriteLock = new Object(); bool data = false; public ReadWriteRunner(int numReadThreads, int numWriteThreads) { writeLock = rwlock.GetWriteLock(); readLock = rwlock.GetReadLock(); readers = new List(numReadThreads); writers = new List(numWriteThreads); AddReadThreads(numReadThreads); AddWriteThreads(numWriteThreads); } private void AddReadThreads(int numThreads) { for (int i = 0; i < numThreads; i++) { readers.Add(new Thread(new ThreadStart(DoRead))); } } private void AddWriteThreads(int numThreads) { for (int i = 0; i < numThreads; i++) { writers.Add(new Thread(new ThreadStart(DoWrite))); } } public void Run(int numItemsToWrite) { itemsToWrite = numItemsToWrite; // Start readers foreach (Thread t in readers) t.Start(); // Start writers foreach (Thread t in writers) t.Start(); // Wait foreach (Thread t in writers) t.Join(); foreach (Thread t in readers) t.Join(); } private void LockReader() { lock (internalReadLock) { readLock.Lock(); readerlocked = true; } } private void UnlockReader() { lock (internalReadLock) { readLock.Unlock(); readerlocked = false; } } private void DoRead() { int readVal = 0; while (stillrun) { // See if there's new data to read lock (dataavailable) { while (!data) { Monitor.Wait(dataavailable); if (stillrun == false) return; } // // Read data LockReader(); // Make sure no writers have the lock Assert.IsFalse(writerlocked); readVal = rwdata; UnlockReader(); } } } private void LockWriter() { lock (internalWriteLock) { writeLock.Lock(); writerlocked = true; } } private void UnlockWriter() { lock (internalWriteLock) { writeLock.Unlock(); writerlocked = false; } } private void DoWrite() { Random randNum = new Random(); while (stillrun) { // Write data LockWriter(); lock (dataavailable) { // Make sure no readers have the lock Assert.IsFalse(readerlocked); rwdata = randNum.Next(100); if (++itemsWritten == itemsToWrite) stillrun = false; data = true; UnlockWriter(); Monitor.PulseAll(dataavailable); } } // Pulse any readers that are still just waiting around. // Without this call, things will deadlock! Monitor.PulseAll(dataavailable); } } }