爱一个人就会要去保护她/他,不管自己有多大的能力,甚至会舍弃掉自己的一部分东西。那个时候才发现对方能够好比自己能够好可以带来更多的满足和快乐的意义。然而只有这种保护是对方愿意接受并且愿意以自己可以的方式来回报这种保护的时候,才可能在2个人心里都产生爱。
锁在生活里面很常见,无论是具体的物理锁还是抽象的密码锁。一般我们会把重要的东西放在一个箱子里,并且给他一个锁以及开锁的钥匙,这样我们每次去找这些东西的时候就不会满屋子一个个的找,就会想到这个重要的箱子里面有自己想要的东西。用锁可以让别人无法获取到那些重要的东西,有的东西可能对很多人很需要,容易发生争抢,有的东西只对某个人很需要,所以用很安全的方式去保护以便不让其他人获取到。
总之,加了锁会让人更有安全感。在程序里面,容易出现不安全的情况是一个共享数据在被多个协程访问的时候,最终的这个共享数据和预期的不一样。因此通过加锁让在一段时间内 只有一个协程可以去访问共享数据,访问结束之后,释放这个锁,让另一个协程以同样的方式去访问共享数据。这样对共享数据的操作变得简单和可以预期。
为了体现是否安全的问题,需要写一种安全的代码和不安全的代码来对比。
package main
import (
"fmt"
"sync"
)
func main() {
var num = 0
var wg sync.WaitGroup
numOfGoroutine := 100
wg.Add(numOfGoroutine)
var lock sync.Mutex
for i := 0; i < numOfGoroutine; i++ {
go func() {
defer wg.Done()
//加锁
lock.Lock()
//不安全的数据操作
num++
//释放锁
lock.Unlock()
}()
}
wg.Wait()
fmt.Println(num)
}
以上是安全的代码,打印结果是5;
package main
import (
"fmt"
"sync"
)
func main() {
var num = 0
var wg sync.WaitGroup
numOfGoroutine := 100
wg.Add(numOfGoroutine)
for i := 0; i < numOfGoroutine; i++ {
go func() {
defer wg.Done()
//不安全的数据操作
num++
}()
}
wg.Wait()
fmt.Println(num)
}
在多次运行不安全的代码,会发现得到的结果可能是不一样的,虽然有些时候得到的也可能是预期的结果。
注意:这里创建wg lock的时候没有使用new或者make等初始化操作,是因为这个2个类型也像int一样不初始化就会有他的0值。
下面是Mutex的0值
{0 0}
Mutex的数据结构也是2个int类型的值
type Mutex struct {
state int32
sema uint32
}
下面是对这个结构的注释
// A Mutex is a mutual exclusion lock. // The zero value for a Mutex is an unlocked mutex. // A Mutex must not be copied after first use.
这是一个互斥锁,0值表示是已经释放锁的,在第一次被使用之后,不能被复制使用。
互斥锁表示这个锁同时只能被一个协程拿到,其他的协程需要等待当前协程释放了锁之后才可以去获取锁。