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 怎样才能让鼠标沿着线条的中心线轨迹移动
  • ¥60 用visual studio编写程序,利用间接平差求解水准网
  • ¥15 Llama如何调用shell或者Python
  • ¥20 谁能帮我挨个解读这个php语言编的代码什么意思?
  • ¥15 win10权限管理,限制普通用户使用删除功能
  • ¥15 minnio内存占用过大,内存没被回收(Windows环境)
  • ¥65 抖音咸鱼付款链接转码支付宝
  • ¥15 ubuntu22.04上安装ursim-3.15.8.106339遇到的问题
  • ¥15 blast算法(相关搜索:数据库)
  • ¥15 请问有人会紧聚焦相关的matlab知识嘛?