代码之家  ›  专栏  ›  技术社区  ›  starttter

通过锁请求时间获取同步的锁

  •  0
  • starttter  · 技术社区  · 7 年前

    我有一个带有goroutine的程序,我们将其称为mainprotation,它锁定一个ressource,在另一端,我们将其命名为goroutine-0 goroutine-1 goroutine-2。。。。这个例程尝试获取锁,在主例程停止后,我需要我的另一个goroutine以同步方式获取锁,我的意思是我想要goroutine-0然后goroutine-1。。。 为了解决这个问题,我所做的是一段时间。时间,用goroutine启动时的time.Now()填充,并使用sync.Cond。 以下是一些代码示例:

    package main
    
    import (
        "fmt"
        "sync"
        "time"
    )
    
    func condition(myTime time.Time, timeSlice []time.Time) bool {
        for _, v := range timeSlice {
            if myTime.After(v) {
                return false
            }
        }
        return true
    }
    
    func removeFromSlice(myTime time.Time, timeSlice []time.Time) {
        var place int
        for i, v := range timeSlice {
            if myTime.Equal(v) {
                place = i
                break
            }
        }
    
        timeSlice = append(timeSlice[:place], timeSlice[place+1:]...)
    }
    
    func main() {
        var m sync.Mutex
        c := sync.NewCond(&m)
    
        c.L.Lock()
        fmt.Println("Locker locked")
        go func() {
            time.Sleep(time.Second * 1)
    
            c.L.Unlock()
            fmt.Println("Locker unlocked")
        }()
    
        var wg sync.WaitGroup
        var timeSlice []time.Time
        wg.Add(100)
    
        for i := 0; i < 100; i++ {
            now := time.Now()
            timeSlice = append(timeSlice, now)
            time.Sleep(time.Nanosecond * 1) // ensure there's at leat 1 nanosec of diff between 2 time.Now
            go func(i int, myTime time.Time) {
                fmt.Printf("Before %d %d\n", i, myTime.Unix())
                c.L.Lock()
                for !condition(myTime, timeSlice) {
                    c.Wait()
                }
                c.L.Unlock()
                removeFromSlice(myTime, timeSlice)
                c.Broadcast()
                wg.Done()
                fmt.Printf("After done %d\n", i)
            }(i, now)
        }
        wg.Wait()
    
        fmt.Println("Hello, playground")
    }
    

    我不认为这是做这类事情的正确方法。它看起来很粗糙,有更好的方法吗?

    --编辑-- 在回答@vorspring之后,我认为最好的方法是对func进行切片,它总是调用切片的第一个元素

    package main
    
    import (
        "fmt"
        "sync"
    )
    
    func makeFunc(id int) func() {
        return func() {
            fmt.Printf("called %d\n", id)
        }
    }
    
    func main() {
        var wg sync.WaitGroup
        var funcSlice []func()
        var m sync.Mutex
    
        for i := 0; i < 5; i++ {
            funcSlice = append(funcSlice, makeFunc(i))
            wg.Add(1)
            go func() {
                defer wg.Done()
                m.Lock()
                defer m.Unlock()
                funcSlice[0]()
                funcSlice = funcSlice[1:]
            }()
        }
        wg.Wait()
        fmt.Println("finished")
    }
    
    1 回复  |  直到 7 年前
        1
  •  2
  •   Vorsprung    7 年前

    给goroutines一个内部id,然后让它们按顺序互相调用。下面是如何工作的示例

    package main
    
    import (
        "fmt"
        "sync"
    )
    
    func main() {
        var wg sync.WaitGroup
        var c [5]chan int
        for i := range c {
            c[i] = make(chan int)
            wg.Add(1)
            go func(id int) {
                defer wg.Done()
                f := <-c[id]
                fmt.Println("called from ", f, ".  My id ", id)
                if id < 4 {
                    fmt.Println(id+1, " next")
                    c[id+1] <- id
                }
                fmt.Println("ending ", id)
            }(i)
        }
        c[0] <- 99
    
        wg.Wait()
        fmt.Println("bye")
    }
    

    https://play.golang.org/p/psF8ISodJU_3