RWMutex в Go не работает должным образом - PullRequest
0 голосов
/ 11 мая 2018

Я написал следующую программу-пример с использованием 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)

}

, когда я запускаю эту программу на детской площадке https://play.golang.org/p/g93UtVxZ2dl Я вижу, что она работает правильно, так как запись происходит только 3 разадля уникальных значений.

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}}

однако, когда я запускаю ту же программу с моего компьютера с Windows 10 (на VS Code), я вижу следующий вывод.

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}}

Я делаю что-то не так?Почему это ведет себя по-разному на моей машине и игровой площадке?

1 Ответ

0 голосов
/ 11 мая 2018

Синхронизация между вызовом на Read и Write отсутствует.Все ваши подпрограммы выполняются одновременно, представьте, что все они дойдут до этой строки, а затем уступят другой подпрограмме:

found := s.Read(sd)

Они все вернут false, потому что ни одна из подпрограммперешли эту точку.Теперь они все переходят на следующую строку и считают, что found == false, поэтому все выполняют s.Write(sd).

. Вам необходимо выполнить чтение и запись без разблокировки.Может быть что-то вроде:

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
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...