• Go的cond和livelock


    cond就是condition的缩写,最近在看的一本书顶上就有很多cond的使用,一看Golang中也有,便小看一下。一句话概括就是条件。

    https://ieevee.com/tech/2019/06/15/cond.html

    https://xargin.com/livelock/

    两个例子

    package main
    
    import (
        "fmt"
        "sync"
        "time"
    )
    
    var sharedRsc = false
    
    func main() {
        var wg sync.WaitGroup
        wg.Add(2)
        m := sync.Mutex{}
        c := sync.NewCond(&m)
    
        go func() {
            c.L.Lock()
            for sharedRsc == false {
                fmt.Println("goroutine1 wait")
                c.Wait()
            }
            fmt.Println("gorountie1 ", sharedRsc)
            c.L.Unlock()
            wg.Done()
        }()
    
        go func() {
            // this go routine wait for changes to the sharedRsc
            c.L.Lock()
            for sharedRsc == false {
                fmt.Println("goroutine2 wait")
                c.Wait()
            }
            fmt.Println("goroutine2", sharedRsc)
            c.L.Unlock()
            wg.Done()
        }()
    
        time.Sleep(2 * time.Second)
        c.L.Lock()
        fmt.Println("main goroutine ready")
        sharedRsc = true
        c.Broadcast()
        fmt.Println("main goroutine broadcast")
        c.L.Unlock()
        wg.Wait()
    }

    输出

    goroutine1 wait
    main goroutine ready
    main goroutine broadcast
    gorountie1  true
    goroutine2 true

    这个解释也很简单就是这个c是一个公用的,c.wait必须要broadcast唤醒。这里的一个小问题是加锁解锁,似乎要人为的关注顺序,否则就会造成活锁

    package main
    
    import (
        "fmt"
        "sync"
        "sync/atomic"
        "time"
    )
    
    func main() {
        cadence := sync.NewCond(&sync.Mutex{})
        go func() {
            for range time.Tick(1*time.Microsecond) {
                cadence.Broadcast()
            }
        }()
    
        takeStep := func() {
            cadence.L.Lock()
            cadence.Wait()
            cadence.L.Unlock()
        }
    
        tryDir := func(name string, dirName string, dir *int32) bool {
            fmt.Printf(name + " " + dirName + "
    ")
            atomic.AddInt32(dir, 1)
            takeStep()
            if atomic.LoadInt32(dir) == 1 {
                fmt.Printf("success")
                return true
            }
            takeStep()
            atomic.AddInt32(dir, -1)
            return false
        }
    
        var left, right int32
        tryLeft := func(name string) bool {
            return tryDir(name, "left", &left)
        }
        tryRight := func(name string) bool {
            return tryDir(name, "right", &right)
        }
        walk := func(wg *sync.WaitGroup, name string) {
            defer wg.Done()
            fmt.Printf("%v is trying to scoot: ", name)
            for i := 0; i < 5; i++ {
                if tryLeft(name) || tryRight(name) {
                    return
                }
            }
            fmt.Printf("
    %v tosses her hands up in exasperation!", name)
        }
    
        var wg sync.WaitGroup
        wg.Add(2)
        go walk(&wg, "alice")
        go walk(&wg, "bob|")
    
        wg.Wait()
    }

    这里我们就是模仿两个协程来竞争一个原子变量,这里的takeStep就是加锁解锁阻塞的关键。

    活锁产生的原因就是并发场景下大家没有协调好加锁顺序,能产生活锁的另一个前提是获取锁用的是 trylock,所谓 trylock,就是 try 一下,如果没 lock 住,就返回加锁失败。如果不是 trylock 的话,不一致的加锁顺序会直接导致死锁。

  • 相关阅读:
    SQL中char,varchar,nvarchar等的异同
    SQL中group by的用法
    如何管理自己的时间
    ref和out
    SQL中的日期时间函数
    SQL中的类型转换
    SQL中的自定义函数Function
    SQL中的模糊查询
    Struct是干什么的
    把普通图片转换成二进制
  • 原文地址:https://www.cnblogs.com/CherryTab/p/13202471.html
Copyright © 2020-2023  润新知