dongpu2727 2015-09-24 22:36
浏览 21
已采纳

为什么大猩猩websocket聊天示例未找到使用sync.RWMutex来访问和编辑地图的必要?

In the chat example there is a file called hub.go.

https://github.com/gorilla/websocket/blob/master/examples/chat/hub.go

I have made some changes to that file and it looks like this:

type hub struct {
    // Registered connections.
    connections map[int64]*connection

    sync.RWMutex

    // Inbound messages from the connections.
    broadcast chan []byte

    // Register requests from the connections.
    register chan *connection

    // Unregister requests from connections.
    unregister chan *connection
}

var wsHub = hub{
    connections: make(map[int64]*connection),
    broadcast:   make(chan []byte),
    register:    make(chan *connection),
    unregister:  make(chan *connection),
}

func (h *hub) init() {
    for {
        select {
        case c := <-h.register:
            h.Lock()
            h.connections[c.userId] = c
            h.Unlock()
        case c := <-h.unregister:
            h.RLock()
            _, ok := h.connections[c.userId]
            h.RUnlock()
            if ok {
                h.Lock()
                delete(h.connections, c.userId)
                h.Unlock()
                close(c.send)
            }
        case m := <-h.broadcast:
            for _, c := range h.connections {
                select {
                case c.send <- m:
                default:
                    close(c.send)
                    delete(h.connections, c.userId)
                }
            }
        }
    }
}

I have added sync.RWMutex to the hub struct but I am not sure if this is necessary. Why is it not included in the example? Maybe I am missing something? Is it overkill to lock and unlock?

And also the last case in the init() method I'm not sure how to lock and unlock because it reads and writes at the same time. Should I use both the Rlock() and Lock()? How would that look like?

  • 写回答

1条回答 默认 最新

  • doupingdiao3546 2015-09-24 22:44
    关注

    A mutex is not required because the single hub goroutine is the only goroutine that accesses the map.

    An alternate approach is to eliminate the Go routine and channels and replace them with functions that use a mutex.

    type hub struct {
      connections map[*connection]bool
      mu sync.Mutex
    }
    
    var h = hub{
       connections: make(map[*connection]bool),
    }
    
    func (h * hub) register(c *connection) {
      h.mu.Lock()
      h.connections[c] = true
    }
    
    func (h *hub) unregister(c *connection) {
      h.mu.Lock()
      if _, ok := h.connections[c]; ok {
         delete(h.connections, c)
         close(c.send)
      }
      h.mu.Unlock()
    }
    
    func (h * hub) broadcast(message []byte) {
      h.mu.Lock()
      for c := range h.connections {
        select {
        case c.send <- m:
        default:
          close(c.send)
          delete(h.connections, c)
        }
      }
      h.mu.Unlock()
    }
    

    It's important to protect close(c.send) and c.send <- m with a mutex. This prevents send on a closed channel.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?