美文网首页
Go 中的协程同步(锁)

Go 中的协程同步(锁)

作者: 浑浑噩噩_邋邋遢遢 | 来源:发表于2017-07-31 21:47 被阅读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())
    }
    
    

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

    相关文章

      网友评论

          本文标题:Go 中的协程同步(锁)

          本文链接:https://www.haomeiwen.com/subject/mwfdlxtx.html