2015年7月11日星期六

Implementing a read-write lock with upgrade capability in Golang

In order to increase the performance of our server system, we began to switch to Golang in web server development a few months ago. One benefit that Golang can offer is "concurrency". This kind of concurrency is different from traditional threading paradigm in the sence that it can evently distribute your work load to your SMP system with little overhead.


However, when we need to access global share objects inside goroutines, concurrency may become bad things. For following reasons: realease,acquire semantic; change visibility, memory fence and others.


1) for operation that can are atomic under assembly language semantic, ensure no stale data was read by using atomic package


2) for other operations that are not atomic proper locking is needed.


Here are the code for simple RW lock with upgrade(mixed in other logic):


func (srv *Server) mapStringToInt(app_version string) uint32{
        srv.sti_mu.RLock()
        //fast path
        if element,exist := srv.string_to_int[app_version];exist {
                srv.sti_mu.RUnlock()
                return element
        }
        srv.sti_mu.RUnlock()
        temp := atomic.AddUint32(&srv.sti_cnt,1)
        srv.sti_mu.Lock()
        if element,exist := srv.string_to_int[app_version];exist {
                srv.sti_mu.Unlock()
                return element
        } else {
                srv.string_to_int[app_version] = temp
                srv.sti_mu.Unlock()
                return temp
        }
}