2016-06-27 3 views
0

goroutines 및 동기화 패키지에 대해 읽었습니다. 내 질문은 ... 다른 goroutines의 데이터에 대한 쓰기를 읽을 때 항상 잠금을 해제해야합니까?goroutine 잠금 및 잠금 해제

예를 들어 제가 설정에서 읽고 싶은 다른 goroutines에

config := make(map[string]string) 

그럼 내 서버에 변수가있다. 동기화를 사용하지 않고 읽는 것이 안전합니까 아니면 그렇지 않은가요?

동기화 패키지를 사용하여 작성해야합니다. 하지만 난

type Cache interface { 
    Get(key string) interface{} 
    Put(key string, expires int64, value interface{}) 
} 

// MemoryCache represents a memory type of cache 
type MemoryCache struct { 
    c map[string]*MemoryCacheValue 
    rw sync.RWMutex 
} 

// MemoryCacheValue represents a memory cache value 
type MemoryCacheValue struct { 
    value interface{} 
    expires int64 
} 

// NewMemoryCache creates a new memory cache 
func NewMemoryCache() Cache { 
    return &MemoryCache{ 
     c: make(map[string]*MemoryCacheValue), 
    } 
} 

// Get stores something into the cache 
func (m *MemoryCache) Get(key string) interface{} { 
    if v, ok := m.c[key]; ok { 
     return v 
    } 
    return nil 
} 

// Put retrieves something from the cache 
func (m *MemoryCache) Put(key string, expires int64, value interface{}) { 
    m.rw.Lock() 
    m.c[key] = &MemoryCacheValue{ 
     value, 
     time.Now().Unix() + expires, 
    } 
    m.rw.Unlock() 
} 

내가 안전 여기에 행동하고 간단한 메모리 캐시 시스템이 아니면 내가 아직도 내가 읽기 전용으로 할 때 잠금 해제를 잠글 필요가

예를 들어

읽기에 대한 확실하지 않다?

답변

6

당신은 경쟁 조건의 세계로 뛰어 들고 있습니다. 일반적인 어법은 ANY 루틴이 임의의 수의 다른 코 루틴/스레드로 읽거나 읽을 수있는 (또는 쓰여질 수있는) 데이터를 쓰거나 변경하면 일종의 동기화가 필요하다는 것입니다 시스템을 제자리에 설치하십시오.

예를 들어지도가 있다고 가정 해 보겠습니다. 그것에는 [ "Joe"] "Smith"와 [ "Sean"] = "Howard"가 있습니다. 한 goroutine [ "조"]의 가치를 읽고 싶어. 또 다른 루틴은 [ "Joe"]를 "Cooper"로 업데이트하는 것입니다. 첫 번째 goroutine은 어느 값을 읽습니까? 어느 goroutine이 데이터에 먼저 도착하는지에 따라 다릅니다. 그것은 경쟁 조건입니다. 동작은 정의되지 않으며 예측할 수 없습니다.

해당 액세스를 제어하는 ​​가장 쉬운 방법은 sync.Mutex입니다. 귀하의 경우, 일부 루틴은 읽기만하고 쓸 필요가 없기 때문에 대신 sync.RWMutex을 사용할 수 있습니다 (주된 차이점은 쓰기를 시도하지 않는 한 어떤 수의 스레드라도 읽을 수 있음).

func ReadSomething(o MutexMap, key string) string { 
    o.RLock() // lock for reading, blocks until the Mutex is ready 
    defer o.RUnlock() // make SURE you do this, else it will be locked permanently 
    return o.m[key] 
} 

을 쓰는 :지도에서 읽을 필요가 루틴에, 당신이 할 것,

type MutexMap struct { 
    m map[string]string 
    *sync.RWMutex 
} 

다음 :

을이 같은 구조를 사용하여지도에이 구워 것
func WriteSomething(o MutexMap, key, value string) { 
    o.Lock() // lock for writing, blocks until the Mutex is ready 
    defer o.Unlock() // again, make SURE you do this, else it will be locked permanently 
    o.m[key] = value 
} 

두 가지 모두 원하는 경우 함수가 아니라 struct의 메서드로 작성할 수 있습니다.


채널을 사용하여 접근 할 수도 있습니다. goroutine에서 실행되는 컨트롤러 구조를 만들고 채널을 통해 요청을합니다. 예 :이 맵이나 캐릭터의 이동 구현에 적용하지 않고, 가지 혼란 둘 때문에

package main 

import "fmt" 

type MapCtrl struct { 
    m  map[string]string 
    ReadCh chan chan map[string]string 
    WriteCh chan map[string]string 
    QuitCh chan struct{} 
} 

func NewMapController() *MapCtrl { 
    return &MapCtrl{ 
     m:  make(map[string]string), 
     ReadCh: make(chan chan map[string]string), 
     WriteCh: make(chan map[string]string), 
     QuitCh: make(chan struct{}), 
    } 
} 

func (ctrl *MapCtrl) Control() { 
    for { 
     select { 
     case r := <-ctrl.ReadCh: 
      fmt.Println("Read request received") 
      retmap := make(map[string]string) 
      for k, v := range ctrl.m { // copy map, so it doesn't change in place after return 
       retmap[k] = v 
      } 
      r <- retmap 
     case w := <-ctrl.WriteCh: 
      fmt.Println("Write request received with", w) 
      for k, v := range w { 
       ctrl.m[k] = v 
      } 
     case <-ctrl.QuitCh: 
      fmt.Println("Quit request received") 
      return 
     } 
    } 
} 

func main() { 
    ctrl := NewMapController() 
    defer close(ctrl.QuitCh) 
    go ctrl.Control() 

    m := make(map[string]string) 
    m["Joe"] = "Smith" 
    m["Sean"] = "Howard" 
    ctrl.WriteCh <- m 

    r := make(chan map[string]string, 1) 
    ctrl.ReadCh <- r 
    fmt.Println(<-r) 
} 

Runnable version

+1

나는 가짜 경주 예를 제거한다. 첫 번째 예제에서'o'와'm'을 섞어서 Mutex 메서드를 포함 된 필드로 참조하면서 '뮤텍스'로 정의합니다. – JimB

+0

권장 사항 당 수정 됨. – Kaedys

관련 문제