指针本身的同步问题
指针本身的同步问题
问题发生的场景
用户可能有两个不同的结构体或变量,每个都保存着自己的指针,现在需要这两个指针变量本身在修改时保持同步。这种情况下,如何让两个独立的变量在修改时互相通知并更新?
两个指针本身被修改了,比如重新指向其他地方,这样就会导致两个内存块中的指针不再同步。比如,假设内存块A和B各自保存一个指针,指向同一个数据对象。如果通过内存块A的指针修改了数据,那么通过B的指针访问时,数据应该已经改变,这没问题。但如果其中一个指针被重新指向另一个地址,另一个指针并不会跟着变,这时候两个内存块中的指针就不一致了。
问题分析
我们在很多场景下都会遇到,多个结构体的定义中包含相同类型的结构体指针。如下:
1
2
3
4
5
6
7
8
9
type A struct {
c *C
}
type B struct {
c *C
}
type C struct {
...
}
假设有这样的情况,我们需要用B的结构体来进行某些操作,会使用到B的c指针指向的内容。B的指针是通过A赋值而来的,自然而然想要与A的c指针保持一致。假设有下面的方法,读者可以思考下调用它会导致什么问题。
1
2
3
4
5
6
7
8
b := &B{c: a.c} // 这里的a.c是指向C的指针
func (a *A) UpdateC(updateC *C) {
a.c = updateC
}
UpdateC(c)
Use(b.c)
UpdateC(nil)
Use(b.c)
没错,此时调用的Use方法里的c是落后的,和a不一致的,会导致出现错误。甚至我们将指针置为空了,此时画面表现应该是空的,但是用B的成员发现还是有数据的,这就是很严重的错误了。
那么如何解决这个问题呢?
其实这个问题和大部分值拷贝问题一样,都是因为指针本身的值被拷贝了,值拷贝产生的问题同样存在在指针拷贝上。
解决方案
二级指针
如果我们持有的是指针的指针,那么改变内部指针值,就可以通过不变的二级指针来同步访问到变化的内部指针值了。下面以玩家的装备信息为例(其实是本人工作中遇到的问题,具体点方便读者理解)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
type EquiptState struct {
equiptProp *Prop
}
type GameState struct {
userId int
equiptState *EquiptState
}
type Bag struct {
usersEquiptStates map[string]*EquiptState
}
func (b *Bag) UpdateEquiptState(userId string, updateProp *Prop) {
b.usersEquiptStates[userId].equiptProp = updateProp
}
func GenerateGameState(userId string, bag * Bag) *GameState {
return &GameState{
userId: userId,
equiptState: bag.usersEquiptStates[userId],
}
}
这样哪怕我们在背包模块中更新玩家的装备状态,发送的快照信息也会实时变化,这样就不会出现指针不一致的问题了。
串行的一致性问题通过指针解决、并行的一致性问题通过锁或原子操作解决。这个理念要牢记于心。
This post is licensed under CC BY 4.0 by the author.