Skip to content

Commit b127c0d

Browse files
committed
thread safety issue
1 parent c66fe6f commit b127c0d

File tree

1 file changed

+18
-10
lines changed

1 file changed

+18
-10
lines changed

Tests/Cache.cs

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,10 @@ private sealed class Pending { internal required K Key; internal required Task<V
1818
private Entry[] _entries;
1919
private Pending? _pending;
2020

21-
public Cache() => _entries = new Entry[2];
22-
public Cache(int capacity) => _entries = new Entry[capacity < 2 ? 2 : BitOperations.RoundUpToPowerOf2((uint)capacity)];
21+
public Cache(int capacity = 2) => _entries = new Entry[capacity <= 2 ? 2 : BitOperations.RoundUpToPowerOf2((uint)capacity)];
2322

24-
public Cache(IEnumerable<KeyValuePair<K, V>> items)
23+
public Cache(IEnumerable<KeyValuePair<K, V>> items) : this()
2524
{
26-
_entries = new Entry[2];
2725
foreach (var (k, v) in items) AddOrUpdate(k, v);
2826
}
2927

@@ -46,9 +44,10 @@ private void AddOrUpdate(K key, V value)
4644
entries[i].Next = entries[bucketIndex].Bucket - 1;
4745
entries[i].Key = key;
4846
entries[i].Value = value;
49-
entries[bucketIndex].Bucket = ++_count;
50-
_version++;
47+
entries[bucketIndex].Bucket = _count + 1;
5148
_entries = entries;
49+
_count++;
50+
_version++;
5251
}
5352

5453
[MethodImpl(MethodImplOptions.NoInlining)]
@@ -72,9 +71,9 @@ public ValueTask<V> GetOrAdd(K key, Func<K, Task<V>> factory)
7271

7372
public ValueTask<V> GetOrAdd<TState>(K key, TState state, Func<K, TState, Task<V>> factory)
7473
{
74+
var hashCode = key.GetHashCode();
7575
var version = Volatile.Read(ref _version);
7676
var entries = Volatile.Read(ref _entries);
77-
var hashCode = key.GetHashCode();
7877
var i = entries[hashCode & (entries.Length - 1)].Bucket - 1;
7978
while (i >= 0)
8079
{
@@ -128,8 +127,8 @@ public void Compact(Func<KeyValuePair<K, V>, bool> keep)
128127
}
129128
}
130129
_count = newIndex;
131-
_version++;
132130
_entries = newEntries;
131+
_version++;
133132
}
134133
}
135134

@@ -191,8 +190,17 @@ private void RemovePending(Pending remove)
191190

192191
public IEnumerator<KeyValuePair<K, V>> GetEnumerator()
193192
{
194-
for (int i = 0; i < _count; i++)
195-
yield return new(_entries[i].Key, _entries[i].Value);
193+
var version = Volatile.Read(ref _version);
194+
var count = _count;
195+
var entries = _entries;
196+
if (version != Volatile.Read(ref _version))
197+
lock (_lock)
198+
{
199+
count = _count;
200+
entries = _entries;
201+
}
202+
for (int i = 0; i < count; i++)
203+
yield return new(entries[i].Key, entries[i].Value);
196204
}
197205

198206
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

0 commit comments

Comments
 (0)