public void Write <T>(T[] instances, Action <T> write) { RMonitor.Enter(_writersMutex); try { var index = RInterlocked.Read(ref _index); var nextIndex = Toggle(index); if (WaitOnFirstWrite) { WaitWhileOccupied(_readIndicator[nextIndex]); // Now we're subject to starvation by (new) readers. } // And mutual exclusion may still be violated. _snoop.BeginWrite(nextIndex); write(instances[nextIndex]); _snoop.EndWrite(nextIndex); // Move subsequent readers to 'next' instance RInterlocked.Exchange(ref _index, nextIndex); // Wait for all readers to finish reading the instance we want to write next WaitWhileOccupied(_readIndicator[index]); // At this point there may be readers, but they must be on nextReadIndex, we can // safely write. _snoop.BeginWrite(index); write(instances[index]); _snoop.EndWrite(index); } finally { RMonitor.Exit(_writersMutex); } }
public void Write <T>(T[] instances, Action <T> write) { RMonitor.Enter(_writersMutex); try { // var readIndex = RUnordered.Read(ref _readIndex); var readIndex = RInterlocked.Read(ref _readIndex); var nextReadIndex = Toggle(readIndex); _snoop.BeginWrite(nextReadIndex); write(instances[nextReadIndex]); _snoop.EndWrite(nextReadIndex); // Move subsequent readers to 'next' instance RInterlocked.Exchange(ref _readIndex, nextReadIndex); // Wait for all readers marked in the 'next' read indicator, // these readers could be reading the 'readIndex' instance // we want to write next var versionIndex = RInterlocked.Read(ref _versionIndex); //var versionIndex = RUnordered.Read(ref _versionIndex); var nextVersionIndex = Toggle(versionIndex); WaitWhileOccupied(_readIndicator[nextVersionIndex]); // Move subsequent readers to the 'next' read indicator RInterlocked.Exchange(ref _versionIndex, nextVersionIndex); // RUnordered.Write(ref _versionIndex, nextVersionIndex); // At this point all subsequent readers will read the 'next' instance // and mark the 'nextVersionIndex' read indicator, so the only remaining potential // readers are the ones on the 'versionIndex' read indicator, so wait for them to finish WaitWhileOccupied(_readIndicator[versionIndex]); // At this point there may be readers, but they must be on nextReadIndex, we can // safely write. _snoop.BeginWrite(readIndex); write(instances[readIndex]); _snoop.EndWrite(readIndex); } finally { RMonitor.Exit(_writersMutex); } }
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); } }