2.通过通信的解决方案
所有的解决方案都是简单的封装了一下 SimpleAccount 来实现保护机制。
共享内存的解决方案
又叫 “通过共享内存来通信”。
这种方案暗示了使用锁机制来预防同时访问和修改共享资源。锁告诉其它处理程序这个资源已经被一个处理程序占用了,因此别的处理程序需要排队直到当前处理程序处理完毕。
让我们来看看 LockingAccount 是怎么实现的:
type LockingAccount struct {
lock sync.Mutex
account *SimpleAccount
}
//封装一下 SimpleAccount
func NewLockingAccount(balance int) *LockingAccount {
return &LockingAccount{account: NewSimpleAccount(balance)}
}
func (acc *LockingAccount) Deposit(amount uint) {
acc.lock.Lock()
defer acc.lock.Unlock()
acc.account.Deposit(amount)
}
func (acc *LockingAccount) Withdraw(amount uint) {
acc.lock.Lock()
defer acc.lock.Unlock()
acc.account.Withdraw(amount)
}
func (acc *LockingAccount) Balance() int {
acc.lock.Lock()
defer acc.lock.Unlock()
return acc.account.Balance()
}
直接明了!注意 lock sync.Lock,lock.Lock(),lock.Unlock()。
这样每次一个附属卡访问银行账号(即共享资源),这个附属卡会自动获得锁直到最后操作完毕。
我们的 LockingAccount 像下面这样使用:
func main() {
balance := 80
b := NewBank(bank.NewLockingAccount(balance))
fmt.Println("初始化余额", b.Balance())
done := make(chan bool)
go func() { b.Withdraw(30, "马伊琍"); done <- true }()
go func() { b.Withdraw(10, "姚笛"); done <- true }()
//等待 goroutine 执行完成
<-done
<-done
fmt.Println("-----------------")
fmt.Println("剩余余额", b.Balance())
}
输出的结果是:
初始化余额 80
[-] 30 马伊琍
[-] 10 姚笛
-----------------
剩余余额 40
现在结果正确了!
在这个例子中第一个处理程序加锁后独享共享资源,其它处理程序只能等待它执行完成。
我们接着看一下执行时的情况,假设马伊琍先拿到了锁:
处理过程
________________
_马伊琍_|__姚笛__
加锁 ><










