On managing a collection of resources which are:
- accessible by name through a global list (e.g. a hash-map)
- accessed concurrently from multiple threads
- ref-counted (Golang lacks "weak references"; see
https://groups.google.com/forum/#!topic/golang-nuts/PYWxjT2v6ps)
Example:
var theList tMap // global
// in thread A, B, C etc
aThing := theList.ref("aThing") // if exists then refcount++, else insert
// use aThing
theList.unref("aThing") // refcount--, if 0 then remove
Edit: I expected to find a recommended pattern for this, but nothing turned up. So I came up with this:
type tMap struct {
set map[string]*tMapSet
updt sync.RWMutex
}
type tMapSet struct {
...
refcount int32
}
func (o *tMap) ref(iId string) *tMapSet {
o.updt.RLock()
aSet := o.set[iId]
if aSet != nil {
atomic.AddInt32(&aSet.refcount, 1)
}
o.updt.RUnlock()
if aSet == nil {
o.updt.Lock()
if aTemp := o.set[iId]; aTemp != nil {
aSet = aTemp
aSet.refcount++
} else {
aSet = &tMapSet{refcount:1}
o.set[iId] = aSet
}
o.updt.Unlock()
}
return aSet
}
func (o *tMap) unref(iId string) {
o.updt.RLock()
aSet := o.set[iId]
aN := atomic.AddInt32(&aSet.refcount, -1) // crash if set[iId] not found
o.updt.RUnlock()
if aN == 0 {
o.updt.Lock()
if aSet.refcount == 0 {
delete(o.set, iId)
}
o.updt.Unlock()
}
}
Suggestions improving the clarity or brevity of the above?