showliuzp 2025-10-22 21:11 采纳率: 83.8%
浏览 2

golang defer使用sync.mutex


//聊天websocket连接数据结构定义
type chat_websocket_conn struct{
    user_conn       *tools.WebSocketConn            //已建立的客户端连接,lu_guild_account_list表id
    msg_chan        chan []byte                     //管道,向客户端写入消息
    client_id       *string                         //生成的唯一id,标识一个客户端
    operator_id     int64                           //当前登陆用户
}

//保存每次登录的用户和websocket的连接
type chat_websocket_map struct{
    map_data map[int64]chat_websocket_conn
    sync.Mutex
}

func new_chat_websocket_init() *chat_websocket_map{
    return &chat_websocket_map{
        map_data : make(map[int64]chat_websocket_conn,0),
    }
}

var websocket_conn_map = new_chat_websocket_init()

func (ws *WsChat) WsChatCreateConn(operator_id int64,w http.ResponseWriter, r *http.Request) (err error){
    defer func(){
        if conn != nil{
            conn.Close()
        }

        if client_id != nil{
            tools.WebSocketConnMapOnce.CloseWebSocketMap(client_id)
        }

        websocket_conn_map.Lock()
        delete(websocket_conn_map.map_data[operator_id])
        websocket_conn_map.Unlock()

    }()

    conn, err := upgrader.Upgrade(w, r, nil)
    if err != nil{
        return
    }

    var (
        client_id = new(string)
        bytes []byte
        conn_detail chat_websocket_conn
        exit_chan = make(chan *string)  //协程退出通知
        streamer_list = make(*[]*iapi.StreamerBaseDetail,0)
        )

    //如果登陆者名下没有主播,关闭连接
    list,err := ws.StreamerList(operator_id)
    if err != nil{
        logx.Error(fmt.Sprintf("tags:%+v,获取当前登陆者的主播,服务异常,关闭连接.err:%+v", ws.LogTag,err))
        conn.Close()
    }

    if len(list) < 1{
        msg_obj = new(iapi.ChatMsg)
        (*msg_obj).Base = iapi.ChatMsgBase{
            Act : types.WS_SYNC_FAIL,
            Msg : "当前登陆者没有主播",
        }

        bytes,_ = pack_msg(msg_obj)
        err = conn.WriteMessage(websocket.TextMessage, bytes)
        if err != nil{
            if !websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseGoingAway) {
                logx.Error(fmt.Sprintf("tags:%+v,获取当前登陆者的主播,发送消息异常,err:%+v", ws.LogTag,err))
                return
            }

            return
        }

        conn.Close()
    }

    //如果连接已存在,则使用已建立的
    if data,ok := websocket_conn_map.map_data[operator_id];ok{
        *client_id = data.client_id

        goto loop
    }

    client_id = ws_conn_obj.CreateWebSocketConn(conn)

    websocket_conn_map.Lock()

    for i,count := 0,len(list); i < count; i++{
        detail := list[i]

        detail := &iapi.StreamerBaseDetail{
            StreamerId      : detail.Id,
            StreamerName    : detail.NickName,
            StreamerAvatar  : detail.Avatar,
        }

        fmt.Printf("数据:%+v\n",detail)
        streamer_list = append(streamer_list,&detail)

    }
    //建立当前登录用户和连接的绑定关系
    conn_detail = chat_websocket_conn{
        user_conn       : tools.WebSocketConnMapOnce.ConnMap[client_id],
        msg_chan        : make(chan []byte,chan_write_buff_limit),  //消息读写管道
        client_id       : client_id,
        streamer_list   : &streamer_list,
        operator_id     : operator_id,
    }

    //为每个登陆者创建一个连接对象,保存在map中
    websocket_conn_map.map_data[operator_id] = conn_detail
websocket_conn_map.Unlock()

    msg_obj = new(iapi.ChatMsg)
    (*msg_obj).Base = iapi.ChatMsgBase{
        Act : types.WS_SYNC_SUCC,
        Msg : "建立连接成功",
    }

    bytes, err = pack_msg(msg_obj)
    if err != nil{
     return
   }
}

我定义了一个defer函数,其中err返回错误,则删除map里保存的websocket连接,在defer里涉及map的操作,我是加锁了,需要加锁么?
  • 写回答

3条回答 默认 最新

  • 阿里嘎多学长 2025-10-22 21:26
    关注

    阿里嘎多学长整理AIGC生成,因移动端显示问题导致当前答案未能完全显示,请使用PC端查看更加详细的解答过程

    理解

    你想问的是关于Go语言中defer关键字和sync.Mutex的使用。具体来说,你想知道在使用defer时,是否可以使用sync.Mutex来保护资源。

    回答

    在Go语言中,defer关键字用于延迟函数的执行,直到函数返回时才执行。sync.Mutex是用于保护共享资源的互斥锁。

    如果你在使用defer时,需要保护共享资源,可以使用sync.Mutex来实现。例如:

    func foo() {
        mu.Lock()
        defer mu.Unlock()
        // 使用共享资源
    }
    

    在上面的例子中,mu.Lock()用于锁定共享资源,defer mu.Unlock()用于在函数返回时解锁共享资源。

    但是,如果你使用defer来保护共享资源,需要注意的是,defer会在函数返回时执行,可能会导致资源释放顺序不正确。因此,需要谨慎使用defer来保护共享资源。

    建议

    如果你需要保护共享资源,建议使用sync.Mutex来实现。例如:

    func foo() {
        mu.Lock()
        // 使用共享资源
        mu.Unlock()
    }
    

    或者使用defer来释放资源,但需要确保资源释放顺序正确。例如:

    func foo() {
        // 使用共享资源
        defer func() {
            // 释放资源
        }()
    }
    

    总结

    在Go语言中,defer关键字和sync.Mutex可以一起使用来保护共享资源。但是需要谨慎使用defer来保护共享资源,确保资源释放顺序正确。

    评论

报告相同问题?

问题事件

  • 创建了问题 10月22日