美文网首页
Go 临界资源

Go 临界资源

作者: 来到了没有知识的荒原 | 来源:发表于2020-07-18 14:51 被阅读0次

    出现临界资源访问问题的代码

    package main
    
    import (
        "fmt"
        "math/rand"
        "time"
    )
    
    var ticket = 10
    
    func main() {
    
        go sellTicket("售票口1")
        go sellTicket("售票口2")
        go sellTicket("售票口3")
        go sellTicket("售票口4")
    
        time.Sleep(3*time.Second)
    }
    
    func sellTicket(name string) {
        rand.Seed(time.Now().UnixNano())
        for {
            if ticket > 0 {
                time.Sleep(time.Duration(rand.Intn(1000))*time.Millisecond)
                fmt.Println(name, "售出", ticket)
                ticket--
            } else {
                break
            }
        }
    }
    

    不要以共享内存的方式去通信,而是以通信的方式共享内存

    • sync
    • 鼓励使用channel

    使用waitgroup实现同步(信号量)

    WaitGroup 同步等待组
    Add() 设置等待组中goroutine的数量
    Wait() 让当前gouroutine处于阻塞状态
    Done() 让等待组中计数器减一

    package main
    
    import (
        "fmt"
        "sync"
    )
    
    var wg sync.WaitGroup
    
    func main() {
    
        wg.Add(2)
        go fun1()
        go fun2()
    
        fmt.Println("main... 阻塞")
        wg.Wait()
        fmt.Println("main ... 完成")
    }
    
    func fun1() {
        for i := 0; i < 5; i++ {
            fmt.Println("func1 ", i)
        }
        wg.Done()
    }
    
    func fun2() {
        defer wg.Done()
        for i := 0; i < 5; i++ {
            fmt.Println("func2 ", i)
        }
    }
    

    当这段程序中wg.Add(2)改为wg.Add(3)的时候,就会因为计数器最终为1,main函数无法解除阻塞,产生死锁。

    mutex解决一开始的临界资源访问问题

    package main
    
    import (
        "fmt"
        "math/rand"
        "sync"
        "time"
    )
    
    var ticket = 10
    var mutex sync.Mutex
    
    func main() {
    
        go sellTicket("售票口1")
        go sellTicket("售票口2")
        go sellTicket("售票口3")
        go sellTicket("售票口4")
    
        time.Sleep(5 * time.Second)
    }
    
    func sellTicket(name string) {
        rand.Seed(time.Now().UnixNano())
        for {
            mutex.Lock()
            if ticket > 0 {
                time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
                fmt.Println(name, "售出", ticket)
                ticket--
            } else {
                mutex.Unlock()
                fmt.Println("票卖完了...")
                break
            }
            mutex.Unlock()
        }
    }
    

    使用WaitGroup让main函数等待四个goroutine完成后再结束
    (替代掉time.Sleep)

    package main
    
    import (
        "fmt"
        "math/rand"
        "sync"
        "time"
    )
    
    var ticket = 10
    var mutex sync.Mutex
    var wg sync.WaitGroup
    
    func main() {
    
        wg.Add(4)
        go sellTicket("售票口1")
        go sellTicket("售票口2")
        go sellTicket("售票口3")
        go sellTicket("售票口4")
    
        wg.Wait()
        fmt.Println("程序结束了")
    }
    
    func sellTicket(name string) {
        rand.Seed(time.Now().UnixNano())
        defer wg.Done()
        for {
            mutex.Lock()
            if ticket > 0 {
                time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
                fmt.Println(name, "售出", ticket)
                ticket--
            } else {
                mutex.Unlock()
                fmt.Println("票卖完了...")
                break
            }
            mutex.Unlock()
        }
    }
    
    

    相关文章

      网友评论

          本文标题:Go 临界资源

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