忽略这个竞争条件可能会出现什么问题?

问题描述 投票:0回答:1

我希望表示一个接收触发器来运行特定任务的服务,但是它仅在给定时间运行该任务一次,而忽略并发触发器。

我的大脑想出了一种非常规的方法来解决这个问题(有时会这样做......)。

package main

import (
    "fmt"
    "sync"
)

func main() {
    var wg sync.WaitGroup
    once := &sync.Once{}
    var trigger = make(chan int)
    done := make(chan bool)
    onceBody := func(v int) func() {
        return func() {
            trigger <- v
        }
    }
    go func() {
        for {
            select {
            case v := <-trigger:
                fmt.Println("Triggered: ", v)
                once = &sync.Once{}
            case <-done:
                return
            }
        }
    }()
    for i := 0; i < 100000; i++ {
        i := i
        wg.Add(1)
        go func() {
            defer wg.Done()
            once.Do(onceBody(i))
        }()
    }
    wg.Wait()
    done <- true
}

我确实知道这个问题有更好的解决方案。我只想了解这种实现可能会出现什么问题。

我知道

once
变量正在发生一种数据竞争,但是,我认为这对于这个特定的用例来说可能并不重要。

闭包的陈旧指针会给GC带来问题吗? 实施过程中可能会出现什么问题?

go concurrency parallel-processing synchronization goroutine
1个回答
0
投票

要在处理触发器时忽略触发器,请启动一个在循环中接收和丢弃触发器的 goroutine。 处理完成后退出循环。

func ignore(trigger chan int, done chan struct{}) {
    for {
        select {
        case v := <-trigger:
            // Discard
        case <-done:
            return
        }
    }
}

func run(trigger chan int, done chan struct{}) {
    for {
        select {
        case v := <-trigger:
            d := make(chan struct{})
            go ignore(trigger, d)
            process(v)
            d <- struct{}{}
        case <-done:
            return
        }
    }
}

在操场上进行演示

© www.soinside.com 2019 - 2024. All rights reserved.