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.

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

报告相同问题?

悬赏问题

  • ¥15 素材场景中光线烘焙后灯光失效
  • ¥15 请教一下各位,为什么我这个没有实现模拟点击
  • ¥15 执行 virtuoso 命令后,界面没有,cadence 启动不起来
  • ¥50 comfyui下连接animatediff节点生成视频质量非常差的原因
  • ¥20 有关区间dp的问题求解
  • ¥15 多电路系统共用电源的串扰问题
  • ¥15 slam rangenet++配置
  • ¥15 有没有研究水声通信方面的帮我改俩matlab代码
  • ¥15 ubuntu子系统密码忘记
  • ¥15 保护模式-系统加载-段寄存器