douzhuangna6906 2018-05-11 09:29
浏览 45
已采纳

Go中的RWMutex无法正常工作

I have written following sample program using sync.RWMutex.

package main

import (
    "fmt"
    "sync"
    "time"
)

// SessionData : capture session id and cc-request-number
type SessionData struct {
    id    string
    reqNo string
}

// SessionCache : cache for the SessionData
type SessionCache struct {
    sess map[SessionData]bool
    sync.RWMutex
}

// InitSessionCache : Init for SessionCache
func InitSessionCache() SessionCache {
    return SessionCache{sess: make(map[SessionData]bool)}
}

// Read : read value from session cache
func (s *SessionCache) Read(sd SessionData) bool {
    s.RLock()
    defer s.RUnlock()

    _, found := s.sess[sd]
    return found
}

func (s *SessionCache) Write(sd SessionData) {
    s.Lock()
    defer s.Unlock()
    fmt.Println("Entry not found for ", sd.id, sd.reqNo, "Creating the entry now")
    s.sess[sd] = true
}

func (s *SessionCache) chkDuplicate(sessionID string, Reqno string) bool {

    sd := SessionData{
        id:    sessionID,
        reqNo: Reqno,
    }

    found := s.Read(sd)
    if !found {
        s.Write(sd)
        return found
    }
    return found
}

func main() {
    mySessionData := InitSessionCache()

    for i := 0; i < 10; i++ {
        go mySessionData.chkDuplicate("session1", "1")
        go mySessionData.chkDuplicate("session1", "1")
        go mySessionData.chkDuplicate("session1", "2")
        go mySessionData.chkDuplicate("session1", "2")
        go mySessionData.chkDuplicate("session1", "4")
        go mySessionData.chkDuplicate("session1", "2")
    }
    time.Sleep(300)
    fmt.Println(mySessionData)

}

when I run this program in playground https://play.golang.org/p/g93UtVxZ2dl I see that it is working correctly as the write happens only 3 times for the unique values.

Entry not found for  session1 1 Creating the entry now
Entry not found for  session1 2 Creating the entry now
Entry not found for  session1 4 Creating the entry now
{map[{session1 1}:true {session1 2}:true {session1 4}:true] {{0 0} 0 0 0 0}}

however when I run the same program from my windows 10 machine (on VS Code) I see following output.

Entry not found for  session1 1 Creating the entry now
Entry not found for  session1 2 Creating the entry now
Entry not found for  session1 2 Creating the entry now
Entry not found for  session1 2 Creating the entry now
Entry not found for  session1 4 Creating the entry now
{map[{session1 1}:true {session1 2}:true {session1 4}:true] {{0 0} 0 0 0 0}}

Am I doing something wrong? Why does this behaves differently on my Machine and Playground?

  • 写回答

1条回答 默认 最新

  • dongxing7530 2018-05-11 11:00
    关注

    There is no syncronisation between the call to Read and Write. All your goroutines are running concurrently, imagine if they all run up to this line and then yield to another goroutine:

    found := s.Read(sd)

    They will all return false because none of the goroutines have moved past this point. Now they all move on to the next line and believe that found == false, so all perform the s.Write(sd).

    You need to perform the Read and Write without unlocking. Maybe something like:

    func (s *SessionCache) TryWrite(sd SessionData) err {
        s.Lock()
        defer s.Unlock()
    
        if _, found := s.sess[sd]; found {
            return fmt.Errorf("Entry already exists")
        }
    
        s.sess[sd] = true
    }
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 matlab有关常微分方程的问题求解决
  • ¥15 perl MISA分析p3_in脚本出错
  • ¥15 k8s部署jupyterlab,jupyterlab保存不了文件
  • ¥15 ubuntu虚拟机打包apk错误
  • ¥199 rust编程架构设计的方案 有偿
  • ¥15 回答4f系统的像差计算
  • ¥15 java如何提取出pdf里的文字?
  • ¥100 求三轴之间相互配合画圆以及直线的算法
  • ¥100 c语言,请帮蒟蒻写一个题的范例作参考
  • ¥15 名为“Product”的列已属于此 DataTable