简单来说,结构体里的字段是map类型,map的值类型是个指针,一个goroutine线程修改指针的值,另一个goroutine读取这个值,是否线程安全?如果不是,大神们有什么建议,怎么修改
场景是这样的,一个goroutine线程会执行 `CreateHealthCheck`,添加一个`status`到`ApiserverHealth`并会启动一个goroutine来修改`readinessProbe`的`ready`字段。另一个goroutine会`GetStatus`查询状态。
```
type ApiserverHealth struct {
manager *Manager
status map[int64]*readinessProbe
stopCh <-chan struct{}
statusLock sync.RWMutex
}
type readinessProbe struct {
ready bool
stopCh <-chan struct{}
client *resty.Client
serverURL string
}
// 每个id的status会启动一个goroutine来执行修改ready字段
func (r *readinessProbe) start() {
probeFunc := func() {
resp, err := r.client.R().Get(r.serverURL)
if err != nil {
// lock ?
r.ready = false
ginfw.ConsoleLogger.Debugf("failed to probe apiserver %s, %v", r.serverURL, err)
}
r.ready = true
}
// 无限循环执行probeFunc,直到r.stopCh关闭
wait.BackoffUntil(probeFunc, wait.NewExponentialBackoffManager(800*time.Millisecond, 30*time.Second, 2*time.Minute, 2.0, 1.0, &clock.RealClock{}), true, r.stopCh)
}
// 另一个线程添加status
func (c *ApiserverHealth) CreateHealthCheck(id int64) {
stopCh := make(chan struct{})
probe := &readinessProbe{
stopCh: stopCh,
client: resty.New(),
serverURL: probePath,
}
c.setStatus(id, probe)
go probe.start()
}
func (c *ApiserverHealth) setStatus(id int64, probe *readinessProbe) {
c.statusLock.Lock()
defer c.statusLock.Unlock()
c.status[id] = probe
}
// 另一个线程会执行这份
func (c *ApiserverHealth) GetStatus(id int64) bool {
c.statusLock.RLock()
defer c.statusLock.RUnlock()
return c.status[id].ready
}
```
更多评论
map 不是线程安全的,并非写 map 就直接挂了 需要并发的话用 sync 里面的 map
```
// Map is like a Go map[interface{}]interface{} but is safe for concurrent use
// by multiple goroutines without additional locking or coordination.
// Loads, stores, and deletes run in amortized constant time.
```
#1
不安全
撇开无关信息,两个goroutine读写同一个变量,必然不安全。
可以考虑 sync/atomic包
可以用对应的LoadInt32和StoreInt32取代bool值
#3