public static void TrimCopies() { bool tookFlag = false; try { try { } finally { tookFlag = Interlocked.CompareExchange(ref _trimFlag, 1, 0) == 0; } if (!tookFlag) return; var old = _oldestRead; SimpleHashSet toTrim = null; while (old != _current && Interlocked.CompareExchange(ref old.ReaderCount, int.MinValue, 0) == 0) { // we do not want to move "old" to an element which still has not finished writing, since // we must maintain the invariant that says _oldestRead.Changes have already been trimmed. if (old.Later.Changes == null) break; // likewise, thanks to that same invariant, we first move forward, then take Changes... old = old.Later; if (toTrim == null) toTrim = new SimpleHashSet(); toTrim.UnionWith(old.Changes); } if (toTrim == null) return; old.Changes = null; _oldestRead = old; var version = old.Stamp; toTrim.TrimCopies(version); } finally { if (tookFlag) Interlocked.Exchange(ref _trimFlag, 0); } }