基于Golang的分布式锁服务实现:代码Bug排查问询
以下是你的代码中存在的几个关键问题:
ReleaseLoginDetails方法存在竞态条件与未同步读写
你在Release方法里先遍历lockstatus查找匹配的测试ID,找到后才对对应索引的mutex加锁修改lockstatus[i]。这里有两个问题:- 遍历
lockstatus时没有加任何锁,属于未同步的读操作,当其他goroutine正在修改lockstatus条目时,当前goroutine的读取会触发数据竞争,违反Go内存模型。 - 从找到匹配条目到加锁修改的间隙,可能有其他goroutine已经修改了该条目的
lockstatus,导致你错误地释放了不属于当前测试的登录信息。
正确做法:应该遍历每个索引时先加锁,再检查lockstatus[i]是否匹配当前测试ID,匹配后再修改并解锁。
- 遍历
AcquireLoginDetails方法中的字段名错误
代码里你写了s.LoginDetails[i].UserID和s.LoginDetails[i].Password,但结构体定义里存储登录信息的字段是data []*LoginDetails,这里明显是笔误,应该改成s.data[i],否则代码无法通过编译。三个切片长度不一致会触发数组越界
lockstatus、data、mu三个切片需要保持相同的长度,否则在遍历或访问元素时会出现数组越界错误。比如如果data的长度大于mu,当i超过mu的长度时,访问s.mu[i]会 panic;反之如果mu更长,访问s.data[i]也会 panic。初始化时必须确保三个切片的长度一致,后续修改时也要同步调整。AcquireLoginDetails中TryLock的逻辑小问题
当你TryLock成功后,如果发现当前lockstatus[i]不为空,解锁后继续遍历,这部分逻辑是对的,但要注意:如果多个goroutine同时竞争同一索引的锁,可能会出现多次TryLock失败的情况,但这属于正常的并发竞争,不过你可以考虑优化遍历顺序,比如采用轮询或者随机索引,避免所有goroutine都从第一个索引开始竞争。
内容的提问来源于stack exchange,提问作者Pawan Kumar

