Skip to content
Permalink
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
using System;
using System.Collections.Generic;
using System.Threading;
using RelaSharp.CLR;
namespace RelaSharp.Examples.CLR
{
public class StarvationLeftRight : IRelaExample
{
public IReadOnlyList<Action> ThreadEntries { get; private set; }
public string Name => "Correct Left-Right implementation that allows writer starvation";
public string Description => ActiveConfig.Description;
public bool ExpectedToFail => ActiveConfig.ExpectedToFail;
private static IRelaEngine RE = RelaEngine.RE;
private IEnumerator<SimpleConfig> _configs;
private SimpleConfig ActiveConfig => _configs.Current;
class ReadIndicator
{
private CLRAtomicLong _numReaders;
public void Arrive()
{
RInterlocked.Increment(ref _numReaders);
}
public void Depart()
{
RInterlocked.Decrement(ref _numReaders);
}
public bool IsEmpty => RInterlocked.Read(ref _numReaders) == 0;
}
class InstanceSnoop
{
private HashSet<long> _reading = new HashSet<long>();
private HashSet<long> _writing = new HashSet<long>();
public void BeginRead(long which)
{
RE.MaybeSwitch();
RE.Assert(!_writing.Contains(which), $"Write in progress during read at {which}");
_reading.Add(which);
}
public void EndRead(long which)
{
RE.MaybeSwitch();
_reading.Remove(which);
RE.Assert(!_writing.Contains(which), $"Write in progress during read at {which}");
}
public void BeginWrite(long which)
{
RE.MaybeSwitch();
RE.Assert(!_reading.Contains(which), $"Read in progress during write at {which}");
RE.Assert(!_writing.Contains(which), $"Write in progress during write at {which}");
_writing.Add(which);
}
public void EndWrite(long which)
{
RE.MaybeSwitch();
RE.Assert(!_reading.Contains(which), $"Write in progress during read at {which}");
_writing.Remove(which);
}
}
class LeftRightLock
{
private readonly Object _writersMutex = new Object();
private ReadIndicator _readIndicator;
private CLRAtomicLong _readIndex;
private InstanceSnoop _snoop = new InstanceSnoop();
public LeftRightLock()
{
_readIndicator = new ReadIndicator();
}
public U Read<T, U>(T[] instances, Func<T, U> read)
{
_readIndicator.Arrive();
try
{
var idx = RInterlocked.Read(ref _readIndex);
_snoop.BeginRead(idx);
var result = read(instances[idx]);
_snoop.EndRead(idx);
return result;
}
finally
{
_readIndicator.Depart();
}
}
public void Write<T>(T[] instances, Action<T> write)
{
RMonitor.Enter(_writersMutex);
try
{
var readIndex = RInterlocked.Read(ref _readIndex);
var nextReadIndex = Toggle(readIndex);
_snoop.BeginWrite(nextReadIndex);
write(instances[nextReadIndex]);
_snoop.EndWrite(nextReadIndex);
RInterlocked.Exchange(ref _readIndex, nextReadIndex);
WaitWhileOccupied(_readIndicator);
_snoop.BeginWrite(readIndex);
write(instances[readIndex]);
_snoop.EndWrite(readIndex);
}
finally
{
RMonitor.Exit(_writersMutex);
}
}
private static void WaitWhileOccupied(ReadIndicator readIndicator)
{
while (!readIndicator.IsEmpty) ;
}
private static long Toggle(long i)
{
return i ^ 1;
}
}
private LeftRightLock _lrLock;
private Dictionary<int, string>[] _instances;
public StarvationLeftRight()
{
ThreadEntries = new List<Action> { ReadThread, ReadThread, WriteThread, WriteThread };
var configList = new List<SimpleConfig>{new SimpleConfig("Seq-cst operations", MemoryOrder.Relaxed, false)};
_configs = configList.GetEnumerator();
}
public void PrepareForIteration()
{
PrepareForNewConfig();
}
public void ReadThread()
{
for(int i = 0; i < 5; ++i)
{
string message = null;
bool read = _lrLock.Read(_instances, d => d.TryGetValue(i, out message));
}
}
public void WriteThread()
{
for(int i = 0; i < 5; ++i)
{
_lrLock.Write(_instances, d => d[i] = $"Wrote This: {i}");
}
}
public void OnBegin()
{
}
public void OnFinished()
{
}
private void SetupActiveConfig()
{
}
private void PrepareForNewConfig()
{
_lrLock = new LeftRightLock();
_instances = new Dictionary<int, string>[2];
_instances[0] = new Dictionary<int, string>();
_instances[1] = new Dictionary<int, string>();
}
public bool SetNextConfiguration()
{
PrepareForNewConfig();
bool moreConfigurations = _configs.MoveNext();
if (ActiveConfig != null)
{
SetupActiveConfig();
}
return moreConfigurations;
}
}
}