SoFunction
Updated on 2025-03-02

Golang thread-safe map implementation

Coroutine-safe maps found on the Internet are all implemented using mutex locks or read and write locks. Here, a single coroutine is used to implement them, that is, all addition, deletion, search and modification operations are integrated into a goroutine, so that there will definitely be no problem of multi-thread concurrent access.

The basic idea is to start a long-running goroutine in the background, block the request req in your channel, and req is divided into different requests, such as reading key, writing key, etc., and then perform various operations in this goroutine.

Example: The Get method sends a request to readSig (channel). The request is a pointer to readReq. ​​When the run method receives the signal, it reads the underlying map and writes the value to readReq's value (value is a channel). The receive value blocked by the Get method, and returns the value when received.

ps: It took more than two hours to finish writing, but I just did a simple test, and I didn’t test in depth, and I didn’t test the performance. In the future, I will test the correctness and how the performance is compared to the locked writing method.

package util
 
type smap struct {
 m      map[interface{}]interface{}
 readSig   chan *readReq
 writeSig   chan *writeReq
 lenSig    chan *lenReq
 terminateSig chan bool
 delSig    chan *delReq
 scanSig   chan *scanReq
}
 
type readReq struct {
 key  interface{}
 value interface{}
 ok  chan bool
}
 
type writeReq struct {
 key  interface{}
 value interface{}
 ok  chan bool
}
 
type lenReq struct {
 len chan int
}
 
type delReq struct {
 key interface{}
 ok chan bool
}
 
type scanReq struct {
 do     func(interface{}, interface{})
 doWithBreak func(interface{}, interface{}) bool
 brea    int
 done    chan bool
}
// NewSmap returns an instance of the pointer of safemap
func NewSmap() *smap {
 var mp smap
  = make(map[interface{}]interface{})
  = make(chan *readReq)
  = make(chan *writeReq)
  = make(chan *lenReq)
  = make(chan *delReq)
  = make(chan *scanReq)
 go ()
 return &mp
}
 
//background function to operate map in one goroutine
//this can ensure that the map is Concurrent security.
func (s *smap) run() {
 for {
 select {
 case read := <-:
  if value, ok := []; ok {
   = value
   <- true
  } else {
   <- false
  }
 case write := <-:
  [] = 
   <- true
 case l := <-:
   <- len()
 case sc := <-:
  if  == 0 {
  for k, v := range  {
   (k, v)
  }
  } else {
  for k, v := range  {
   ret := (k, v)
   if ret {
   break
   }
  }
  }
   <- true
 case d := <-:
  delete(, )
   <- true
 case <-:
  return
 }
 }
}
 
//Get returns the value of key which provided.
//if the key not found in map, ok will be false.
func (s *smap) Get(key interface{}) (interface{}, bool) {
 req := &readReq{
 key: key,
 ok: make(chan bool),
 }
  <- req
 ok := <-
 return , ok
}
 
//Set set the key and value to map
//ok returns true indicates that key and value is successfully added to map
func (s *smap) Set(key interface{}, value interface{}) bool {
 req := &writeReq{
 key:  key,
 value: value,
 ok:  make(chan bool),
 }
  <- req
 return <- //TODO is temporarily synchronous, and there may be problems with the use of asynchronous.}
 
//Clear clears all the key and value in map.
func (s *smap) Clear() {
  = make(map[interface{}]interface{})
}
 
//Size returns the size of map.
func (s *smap) Size() int {
 req := &lenReq{
 len: make(chan int),
 }
  <- req
 return <-
}
 
//terminate  function. this function is usually called for debug.
//after this do NOT use smap again, because it can make your program block.
func (s *smap) TerminateBackGoroutine() {
  <- true
}
 
//Del delete the key in map
func (s *smap) Del(key interface{}) bool {
 req := &delReq{
 key: key,
 ok: make(chan bool),
 }
  <- req
 return <-
}
 
//scan the map. do is a function which operate all of the key and value in map
func (s *smap) EachItem(do func(interface{}, interface{})) {
 req := &scanReq{
 do:  do,
 brea: 0,
 done: make(chan bool),
 }
  <- req
 <-
}
 
//scan the map util function 'do' returns true. do is a function which operate all of the key and value in map
func (s *smap) EachItemBreak(do func(interface{}, interface{}) bool, condition bool) {
 req := &scanReq{
 doWithBreak: do,
 brea:    1,
 done:    make(chan bool),
 }
  <- req
 <-
}
 
//Exists checks whether the key which provided is exists in map
func (s *smap) Exists(key interface{}) bool {
 if _,found := (key); found {
 return true
 }
 return false
}

Github address:/hackssssss/safemap

The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.