Я пытаюсь реализовать схему доступа к карте, которая позволяет несколько
читатели и только один писатель и где ключ записывается на карту только один раз.
Я хочу убедиться, что ключ, если он существует, размещается на карте только один раз. А затем, как только ключ добавлен, читатели получают значение с карты.
Кажется, это правильно, хотя основной поток может завершиться до того, как завершатся все процедуры, поэтому я не всегда вижу напечатанный 10 Выход. Это правильный шаблон реализации?
package main
import (
"fmt"
"sync"
"time"
)
var downloads map[string]*sync.WaitGroup
var downloadsLock sync.RWMutex
func concurrentAccessTest() {
// Acquire the read lock to check if the items is already there.
downloadsLock.RLock()
if wg, ok := downloads["item"]; ok {
// Item exists
downloadsLock.RUnlock()
wg.Wait()
} else {
downloadsLock.RUnlock()
fmt.Println("Upgrade Lock")
// Item does not exist we need to add it to the map
downloadsLock.Lock()
fmt.Println("Writer lock obtained")
// Check another thread hasn't gone down this path and added the item to the map
if wg, ok := downloads["item"]; ok {
// Item exists, no need to add it, unlock and wait
downloadsLock.Unlock()
wg.Wait()
fmt.Println("Ok, now we can proceed")
} else {
// We are first in. Add and unlock
wg = &sync.WaitGroup{}
downloads["item"] = wg
downloadsLock.Unlock()
wg.Add(1)
fmt.Println("Do some time consuming stuff!")
time.Sleep(5 * time.Second)
wg.Done()
}
}
fmt.Println("Exit")
}
func main() {
downloads = make(map[string]*sync.WaitGroup)
// Add to the map
for i := 0; i < 10; i++ {
go concurrentAccessTest()
}
concurrentAccessTest()
// Wait for all threads to exit
fmt.Println("Done!")
}