GO通道,避免死锁(比读取所有通道更好的解决方案)

时间:2018-11-28 16:35:18

标签: go deadlock channel

我有一个输入数字的基本频道 稍后通过公式修改自身 有3个通道可以根据不同情况接收值 发送次数的平均值必须介于两个值之间,如if循环所示

if average < 10 {
        channel <- average
    }
    if average > 0 && average < 100 {
        channel1 <- average
    }
    if average > 75 && average < 200 {
        channel2 <- average
    }

我面临的问题是在避免死锁的情况下,我必须做一个奇怪的if循环,该循环读取所有已发送的值,但从不读取

之所以发生这种情况,是因为 averageisOK 全局值变为false,但是至少还有2个值仍在等待读取,或者也许这就是我的理解。

因此有可能避免奇怪的循环并对此有更好的解决方案。

package main

import(
    "fmt"
    "sync"
) 

var wait sync.WaitGroup
var averageIsOk = true
var doneSendersCount = 0
var counterIsDone = false

func main() {
    counterChannel := make(chan float64)
    channel := make(chan float64)
    channel1 := make(chan float64)
    channel2 := make(chan float64)

    for i := 0; i < 10; i++ {
        wait.Add(1)
        go send(counterChannel, float64(i))
    }

    wait.Add(1)
    go count(counterChannel, channel, channel1, channel2)

    wait.Add(1)
    go print(channel, 1)

    wait.Add(1)
    go print(channel1, 2)

    wait.Add(1)
    go print(channel2, 3)

    wait.Wait()
}

func send (counterChannel chan<- float64, startNumber float64){
    defer wait.Done()
    i := startNumber

    for averageIsOk {
        counterChannel <- i
        i = i * i - 4 * i + 1
    }

    doneSendersCount++
}

func count (counterChannel <-chan float64, channel chan<- float64, channel1 chan<- float64, channel2 chan<- float64){
    defer wait.Done()

    var averageArray [15]float64
    for i := 0; i < 15; i++ {
        averageArray[i] = 0
        }

    for averageIsOk {
        receivedNumber := <- counterChannel

        for i := 14; i > 0; i-- {
            averageArray[i] = averageArray[i - 1]
        }

        averageArray[0] = receivedNumber

        average := 0.0
        for i := 0; i < 15; i++ {
            average += averageArray[i]
        }
        average = average / 15

        if average < 10 {
            channel <- average
        }
        if average > 0 && average < 100 {
            channel1 <- average
        }
        if average > 75 && average < 200 {
            channel2 <- average
        }

        if average > 200 {

            close(channel)
            close(channel1)
            close(channel2)
            averageIsOk = false
        }
    }

    counterIsDone = true
    for doneSendersCount != 10 {
        select {
        case <- counterChannel:
            break
        default:
            break
        }
    }
}

func print (printChannel <-chan float64, printerNumber int){
    defer wait.Done()

    for averageIsOk {
        receivedNumber := <- printChannel
        fmt.Println("Kanalas nr-", printerNumber, ":", receivedNumber)
    }

    for !counterIsDone {
        select {
        case <- printChannel:
            break
        default:
            break
        }
    }
}

0 个答案:

没有答案