Skip to content

Commit b93435f

Browse files
committed
fixed race condition
#16
1 parent b0cd493 commit b93435f

File tree

2 files changed

+62
-7
lines changed

2 files changed

+62
-7
lines changed

cache.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ type Cache[K comparable, V any] struct {
7373
cache Interface[K, *Item[K, V]]
7474
expirations map[K]chan struct{}
7575
// mu is used to do lock in some method process.
76-
mu sync.RWMutex
76+
mu sync.Mutex
7777
}
7878

7979
// Option is an option for cache.
@@ -140,8 +140,8 @@ func New[K comparable, V any](opts ...Option[K, V]) *Cache[K, V] {
140140

141141
// Get looks up a key's value from the cache.
142142
func (c *Cache[K, V]) Get(key K) (value V, ok bool) {
143-
c.mu.RLock()
144-
defer c.mu.RUnlock()
143+
c.mu.Lock()
144+
defer c.mu.Unlock()
145145
item, ok := c.cache.Get(key)
146146
if !ok {
147147
return
@@ -187,8 +187,8 @@ func (c *Cache[K, V]) doneWatchExpiration(key K) {
187187

188188
// Keys returns the keys of the cache. the order is relied on algorithms.
189189
func (c *Cache[K, V]) Keys() []K {
190-
c.mu.RLock()
191-
defer c.mu.RUnlock()
190+
c.mu.Lock()
191+
defer c.mu.Unlock()
192192
return c.cache.Keys()
193193
}
194194

@@ -201,8 +201,8 @@ func (c *Cache[K, V]) Delete(key K) {
201201

202202
// Contains reports whether key is within cache.
203203
func (c *Cache[K, V]) Contains(key K) bool {
204-
c.mu.RLock()
205-
defer c.mu.RUnlock()
204+
c.mu.Lock()
205+
defer c.mu.Unlock()
206206
_, ok := c.cache.Get(key)
207207
return ok
208208
}

cache_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
package cache_test
22

33
import (
4+
"math/rand"
45
"sync"
56
"testing"
67

78
cache "github.com/Code-Hex/go-generics-cache"
9+
"github.com/Code-Hex/go-generics-cache/policy/clock"
10+
"github.com/Code-Hex/go-generics-cache/policy/fifo"
11+
"github.com/Code-Hex/go-generics-cache/policy/lfu"
12+
"github.com/Code-Hex/go-generics-cache/policy/lru"
13+
"github.com/Code-Hex/go-generics-cache/policy/mru"
814
)
915

1016
func TestMultiThreadIncr(t *testing.T) {
@@ -48,3 +54,52 @@ func TestMultiThreadDecr(t *testing.T) {
4854
t.Errorf("want %v but got %v", 0, counter)
4955
}
5056
}
57+
58+
func TestMultiThread(t *testing.T) {
59+
cases := []struct {
60+
name string
61+
policy cache.Option[int, int]
62+
}{
63+
{
64+
name: "LRU",
65+
policy: cache.AsLRU[int, int](lru.WithCapacity(10)),
66+
},
67+
{
68+
name: "MRU",
69+
policy: cache.AsMRU[int, int](mru.WithCapacity(10)),
70+
},
71+
{
72+
name: "FIFO",
73+
policy: cache.AsFIFO[int, int](fifo.WithCapacity(10)),
74+
},
75+
{
76+
name: "Clock",
77+
policy: cache.AsClock[int, int](clock.WithCapacity(10)),
78+
},
79+
{
80+
name: "LFU",
81+
policy: cache.AsLFU[int, int](lfu.WithCapacity(10)),
82+
},
83+
}
84+
for _, tc := range cases {
85+
tc := tc
86+
t.Run(tc.name, func(t *testing.T) {
87+
c := cache.New(tc.policy)
88+
var wg sync.WaitGroup
89+
for i := int64(0); i < 100; i++ {
90+
wg.Add(1)
91+
go func(i int64) {
92+
defer wg.Done()
93+
m := rand.New(rand.NewSource(i))
94+
for n := 0; n < 100; n++ {
95+
key := m.Intn(100000)
96+
c.Set(key, m.Intn(100000))
97+
c.Get(key)
98+
}
99+
}(i)
100+
}
101+
102+
wg.Wait()
103+
})
104+
}
105+
}

0 commit comments

Comments
 (0)