建设一个网站思路,电脑建立网站平台,next 主题wordpress,创世网络网站建设我先声明一下#xff0c;并不是真的加锁失效#xff0c;而是我之前的理解有误#xff0c;导致看起来像是加锁失效一样。于是乎记录一下#xff0c;加深一下印象。
我之前有个理解误区#xff08;不知道大家有没有#xff0c;有的话赶紧纠正一下——其实也是因为我这块的…我先声明一下并不是真的加锁失效而是我之前的理解有误导致看起来像是加锁失效一样。于是乎记录一下加深一下印象。
我之前有个理解误区不知道大家有没有有的话赶紧纠正一下——其实也是因为我这块的知识掌握不牢固导致的觉得只要是加锁后在我主动调用解锁之前这个块范围内的变量一定不会被其他地方修改。后来验证发现我大错特错了。
起因
最近在学习 sync.Mutex 加锁时写了下面一段代码进行练习。
package mainimport (fmtsynctime
)type Info struct {mu sync.MutexValue string
}func Update(info *Info) {fmt.Printf(%s: before update. Value: %s\n, time.Now().Format(timeFormat), info.Value)info.mu.Lock()defer info.mu.Unlock()time.Sleep(2 * time.Second)fmt.Printf(%s: in update. Value: %s\n, time.Now().Format(timeFormat), info.Value)info.Value updatefmt.Printf(%s: after update. Value: %s\n, time.Now().Format(timeFormat), info.Value)
}const timeFormat 2006-01-02 15:04:05func main() {fmt.Printf(%s: main start\n, time.Now().Format(timeFormat))info : Info{}var wg sync.WaitGroupwg.Add(1)go func() {defer wg.Done()Update(info)}()time.Sleep(time.Second)info.Value mainfmt.Printf(%s: in main. Value: %s\n, time.Now().Format(timeFormat), info.Value)wg.Wait()
}按照我原先上面的理解Update() 函数当中before update 和 in update 中对应结构体的值应该是不会变的毕竟我加了锁。然而从运行结果发现Update() 函数执行期间结构体变量的 Value 竟然还是被外部主线程修改了。 分析
那么为什么会这样呢明明 Update() 里边已经添加了锁为什么执行期间还是会被其他地方修改呢
最后发现究其原因还是在于主线程修改变量的值的时候没有先判断锁 mu 是否已经释放就直接进行了修改操作。
主线程中加上获取锁的操作后会先判断当前锁是否被释放如果没被释放就会一直进行等待直到锁释放后才继续执行后面的操作。 输出结果也和预期保持一致 。
2024-04-16 23:59:13: main start
2024-04-16 23:59:13: before update. Value:
2024-04-16 23:59:15: in update. Value:
2024-04-16 23:59:15: after update. Value: update
2024-04-16 23:59:15: in main. Value: main
正常来说锁是要配合多 goroutine 来使用的 对于单线程来说由于没有其他线程进行资源竞争加锁的意义不大对于多 goroutine 而言对于获取和释放锁的时机应该由应用程序合理控制。关于锁的使用还有一些其他注意事项这块也一并写一下。 在一个 goroutine 获得 Mutex 后其他 goroutine 只能等到这个 goroutine 释放该 Mutex使用 Lock() 加锁后不能再继续对其加锁直到利用 Unlock() 解锁后才能再加锁在 Lock() 之前使用 Unlock() 会导致 panic 异常已经锁定的 Mutex 并不与特定的 goroutine 相关联这样可以利用一个 goroutine 对其加锁再利用其他 goroutine 对其解锁在同一个 goroutine 中的 Mutex 解锁之前再次进行加锁会导致死锁适用于读写不确定并且只有一个读或者写的场景
缓冲通道实现互斥逻辑
当然我们还可以通过缓冲为1的通道实现互斥锁的逻辑。
package mainimport (fmtsynctime
)type Info struct {Value string
}func Update(info *Info, sem chan bool) {fmt.Printf(%s: before update. Value: %s\n, time.Now().Format(timeFormat), info.Value)sem - truedefer func() {- sem}()time.Sleep(2 * time.Second)fmt.Printf(%s: in update. Value: %s\n, time.Now().Format(timeFormat), info.Value)info.Value updatefmt.Printf(%s: after update. Value: %s\n, time.Now().Format(timeFormat), info.Value)
}const timeFormat 2006-01-02 15:04:05func main() {sem : make(chan bool, 1)fmt.Printf(%s: main start\n, time.Now().Format(timeFormat))info : Info{}var wg sync.WaitGroupwg.Add(1)go func() {defer wg.Done()Update(info, sem)}()time.Sleep(time.Second)sem - trueinfo.Value mainfmt.Printf(%s: in main. Value: %s\n, time.Now().Format(timeFormat), info.Value)- semwg.Wait()
}2024-04-17 00:26:25: main start
2024-04-17 00:26:25: before update. Value:
2024-04-17 00:26:26: in main. Value: main
2024-04-17 00:26:27: in update. Value: main
2024-04-17 00:26:27: after update. Value: update