Go 中的协程同步(锁)

2017-07-31  本文已影响0人  浑浑噩噩_邋邋遢遢

先来看一个简单的例子,在不运行的前提下猜测结果是什么
这里模仿两个人同时刷卡的操作,猜测最后剩余多少钱

package main

import (
    "time"
    "fmt"
)

type Account struct {
    money int
}

func (a *Account)DoPre()  {
    time.Sleep(time.Second)    // 模仿银行进行检测
}

func (a *Account)GetGongzi(n int)  {
    a.money += n
}
func (a *Account) GiveWife(n int) {
    if a.money > n {
        a.DoPre()
        a.money -= n
    }
}

func (a *Account)Buy(n int)  {
    if a.money > n {
        a.DoPre()
        a.money -= n
    }
}

func (a *Account) Left() int {
    return a.money
}


func main() {
    var account Account
    account.GetGongzi(10)
    go account.GiveWife(6)  // 媳妇花6块
    go account.Buy(5)           // 同时自己花5块
    time.Sleep(2 * time.Second)     // 等待程序全部执行完毕
    fmt.Println(account.Left())
}
结果为-1.

是不是感觉很费解。原因是当媳妇和自己在花钱的时候,同时抢到了相同的工资数(我们启动了2个协程),经过判断都成立,则进入sleep 1秒钟。 这时无论如何都会减去该花的钱。所以最后结果为 -1.

解决办法,为数据加锁,使其只有一人操作数据。

当然,解决的办法有很多种,这只是go里面比较好的解决办法

sync.Mutex
package main

import (
    "time"
    "fmt"
    "sync"
)

type Account struct {
    flag sync.Mutex     // 使用一种复式变量, 只有一个人锁住,其他人就会sleep 直到解锁
    money int
}

func (a *Account)DoPre()  {
    time.Sleep(time.Second)    // 模仿银行进行检测
}

func (a *Account)GetGongzi(n int)  {
    a.money += n
}
func (a *Account) GiveWife(n int) {
    a.flag.Lock()       // 锁住
    if a.money > n {
        a.DoPre()
        a.money -= n
    }
    a.flag.Unlock()     // 释放锁
}

func (a *Account)Buy(n int)  {
    a.flag.Lock()
    if a.money > n {
        a.DoPre()
        a.money -= n
    }
    a.flag.Unlock()
}

func (a *Account) Left() int {
    return a.money
}


func main() {
    var account Account
    account.GetGongzi(10)
    go account.GiveWife(6)  // 媳妇花6块
    go account.Buy(5)           // 同时自己花5块
    time.Sleep(2 * time.Second)     // 等待程序全部执行完毕
    fmt.Println(account.Left())
}

这样结果就合乎逻辑了!!!

上一篇下一篇

猜你喜欢

热点阅读