问题描述
下面是一段用 Go 编写的代码,取自 Raft Locking Advice,规则 5:
rf.mu.Lock()
rf.currentTerm += 1
rf.state = Candidate
for <each peer> {
go func() {
rf.mu.Lock()
args.Term = rf.currentTerm
rf.mu.Unlock()
Call("Raft.RequestVote",&args,...)
// handle the reply...
} ()
}
rf.mu.Unlock()
Raft 是某种共识算法,rf 指的是 Raft。上面的代码试图做的是,领导者正在向其所有对等方发送 RPC 请求,要求投票。正如代码后面的段落所指出的,这段代码并不理想,因为 rf.currentTerm 可能在子例程被触发之前已经改变了。目标是让 rf 的状态在其同行投票时保持不变。
我的补救方法是使用等待组让代码在最后一个 rf.mu.Unlock
之前等待。那肯定会解决提到的问题。然而,建议中的规则 4 指出:it's usually a bad idea to hold a lock while doing anything that might wait
.
解决这个问题的一种方法是让创建的 goroutine 使用外部代码持有锁时制作的 rf.currentTerm 副本。
但我不太确定这意味着什么。
解决方法
您可以将参数传递给 go 例程函数,例如:
rf.mu.Lock()
rf.currentTerm += 1
rf.state = Candidate
for <each peer> {
go func(ct CurrentTerm) {
rf.mu.Lock()
args.Term = ct
rf.mu.Unlock()
Call("Raft.RequestVote",&args,...)
// handle the reply...
} (rt.currentTerm)
}
rf.mu.Unlock()
如果不了解您要实现的目标,我不确定这是最佳解决方案。