如何使用sync.Cond对在无限循环上运行的goroutine进行单元测试?

时间:2016-04-28 18:33:54

标签: go synchronization mutex

我正在尝试对在无限循环上运行的通道进行单元测试。我想我已经找到了一种方法,但我不确定它是否是使用条件变量的有效方法。此外,我不确定这种方法是否容易出现竞争状况。因为for循环在它自己的goroutine上运行,所以当我到达" cond.Wait()时,通道是否可能被耗尽?"如果发生这种情况,我会永远挂起吗在我看过使用条件变量的所有例子中,它们通常伴随着围绕等待的for循环。我在这需要吗?我的问题:我在这里使用的方法有什么问题吗?这是条件变量的有效/惯用吗?

package main

import (
    "fmt"
    "sync"
)

var doStuffChan chan bool
var cond *sync.Cond
var result string

func main() {
    doStuffChan = make(chan bool, 10)
    cond = &sync.Cond{L: &sync.Mutex{}}
    go startDoStuffLoop()

    doStuffChan <- true

    cond.L.Lock()
    cond.Wait()
    cond.L.Unlock()

    fmt.Println(result)
}

func startDoStuffLoop() {
    for {
        <-doStuffChan
        result = "success"
        cond.Broadcast()
    }
}

1 个答案:

答案 0 :(得分:2)

在我看来,你的所有假设都是正确的。为避免渠道耗尽,请使用

close(doStuffChan)

而不是doStuffChan <- true,因为您可以永久地从封闭频道收到nil。 他们围绕等待循环检查cond之前是真的,因为它在大多数情况下是一个条件。如果您不想在频道中关闭频道保护信令并使用Lock进行广播,这会使操作优先于确定性。

func main() {
    doStuffChan = make(chan bool)
    cond = &sync.Cond{L: &sync.Mutex{}}
    go startDoStuffLoop()

    cond.L.Lock()
    doStuffChan <- true
    cond.Wait()
    cond.L.Unlock()

    fmt.Println(result)
}

func startDoStuffLoop() {
    for {
        <-doStuffChan
        result = "success"
        cond.L.Lock()
        cond.Broadcast()
        cond.L.Unlock()
    }
}

看到它有效https://play.golang.org/p/1S6VW7nIoV但两个版本都是线程安全的。