如果 p 不为 expunged,和 entry 相关联的这个 value 可以被原子地更新;如果 p == expunged,那么仅当它初次被设置到 m.dirty 之后,才可以被更新。
整体用一张图来表示:

Store
先来看 expunged:
var expunged = unsafe.Pointer(new(interface{}))
它是一个指向任意类型的指针,用来标记从 dirty map 中删除的 entry。
// Store sets the value for a key.
func (m *Map) Store(key, value interface{}) {
// 如果 read map 中存在该 key 则尝试直接更改(由于修改的是 entry 内部的 pointer,因此 dirty map 也可见)
read, _ := m.read.Load().(readOnly)
if e, ok := read.m[key]; ok && e.tryStore(&value) {
return
}
m.mu.Lock()
read, _ = m.read.Load().(readOnly)
if e, ok := read.m[key]; ok {
if e.unexpungeLocked() {
// 如果 read map 中存在该 key,但 p == expunged,则说明 m.dirty != nil 并且 m.dirty 中不存在该 key 值 此时:
// a. 将 p 的状态由 expunged 更改为 nil
// b. dirty map 插入 key
m.dirty[key] = e
}
// 更新 entry.p = value (read map 和 dirty map 指向同一个 entry)
e.storeLocked(&value)
} else if e, ok := m.dirty[key]; ok {
// 如果 read map 中不存在该 key,但 dirty map 中存在该 key,直接写入更新 entry(read map 中仍然没有这个 key)
e.storeLocked(&value)
} else {
// 如果 read map 和 dirty map 中都不存在该 key,则:
// a. 如果 dirty map 为空,则需要创建 dirty map,并从 read map 中拷贝未删除的元素到新创建的 dirty map
// b. 更新 amended 字段,标识 dirty map 中存在 read map 中没有的 key
// c. 将 kv 写入 dirty map 中,read 不变
if !read.amended {
// 到这里就意味着,当前的 key 是第一次被加到 dirty map 中。
// store 之前先判断一下 dirty map 是否为空,如果为空,就把 read map 浅拷贝一次。
m.dirtyLocked()
m.read.Store(readOnly{m: read.m, amended: true})
}
// 写入新 key,在 dirty 中存储 value
m.dirty[key] = newEntry(value)
}
m.mu.Unlock()
}
整体流程:
如果在 read 里能够找到待存储的 key,并且对应的 entry 的 p 值不为 expunged,也就是没被删除时,直接更新对应的 entry 即可。 第一步没有成功:要么 read 中没有这个 key,要么 key 被标记为删除。则先加锁,再进行后续的操作。 再次在 read 中查找是否存在这个 key,也就是 double check 一下,这也是 lock-free 编程里的常见套路。如果 read 中存在该 key,但 p == expunged,说明 m.dirty != nil 并且 m.dirty 中不存在该 key 值 此时: a. 将 p 的状态由 expunged 更改为 nil;b. dirty map 插入 key。然后,直接更新对应的 value。 如果 read 中没有此 key,那就查看 dirty 中是否有此 key,如果有,则直接更新对应的 value,这时 read 中还是没有此 key。 最后一步,如果 read 和 dirty 中都不存在该 key,则:a. 如果 dirty 为空,则需要创建 dirty,并从 read 中拷贝未被删除的元素;b. 更新 amended 字段,标识 dirty map 中存在 read map 中没有的 key;c. 将 k-v 写入 dirty map 中,read.m 不变。最后,更新此 key 对应的 value。









