gpt4 book ai didi

go - 如何停止所有等待 sync.Cond 的 goroutines?

转载 作者:行者123 更新时间:2023-12-01 20:02:43 25 4
gpt4 key购买 nike

我写了一个队列类

type Queue struct {
data []interface{}
cond *sync.Cond
}

func New() Queue {
return Queue{
data: []interface{}{},
cond: sync.NewCond(&sync.Mutex{}),
chanStop: make(chan interface{}),
}
}

func (q *Queue) Push(val interface{}) {
q.cond.L.Lock()

q.data = append(q.data, val)

q.cond.Signal()
q.cond.L.Unlock()
}

func (q *Queue) Pop() (interface{}, bool) {

q.cond.L.Lock()
for len(q.data) == 0 {
q.cond.Wait()
}

retVal := q.data[0]

q.data = q.data[1:]

q.cond.L.Unlock()

return retVal, true
}

func (q *Queue) Close() {

}

如果队列为空 Pop() 调用者将被阻塞。有什么方法可以停止等待任何 Cond 调用用 Pop() 阻止的所有例程?

当然我可以做类似的事情

type Queue struct {
data []interface{}
cond *sync.Cond
chanStop chan interface{}
}


func (q *Queue) Pop() (interface{}, bool) {

var retVal interface{}
retFlag := false

select {
case <-q.chanStop:

case <-func() <-chan interface{} {
out := make(chan interface{})

go func() {
defer close(out)

q.cond.L.Lock()
for len(q.data) == 0 {
q.cond.Wait()
}

retVal = q.data[0]
retFlag = true

q.data = q.data[1:]

q.cond.L.Unlock()
}()
return out
}():
}

return retVal, retFlag
}

func (q *Queue) Close() {
close(q.chanStop)
}

但也许有一些方法可以避免所有这些 select 冗长的等待?

更新:

实际上可能是这样做的:

package queue

import "sync"

type Queue struct {
data []interface{}
cond *sync.Cond
stop bool
}

func New() Queue {
return Queue{
data: []interface{}{},
cond: sync.NewCond(&sync.Mutex{}),
stop: false,
}
}

func (q *Queue) Push(val interface{}) {
q.cond.L.Lock()

q.data = append(q.data, val)

q.cond.Signal()
q.cond.L.Unlock()
}

func (q *Queue) Pop() (interface{}, bool) {
q.cond.L.Lock()
for len(q.data) == 0 && !q.stop {
q.cond.Wait()
}

if q.stop {
q.cond.L.Unlock()
return nil, false
}

retVal := q.data[0]

q.data = q.data[1:]

q.cond.L.Unlock()

return retVal, true
}

func (q *Queue) Close() {
q.cond.L.Lock()

q.stop = true

q.cond.Broadcast()
q.cond.L.Unlock()
}

是的,sync.Cond 太奇怪了。

最佳答案

您可以使用 Cond.Broadcast() 唤醒所有在 Pop() 中等待的客户端,但是如果 q.data 为空并且没有任何可返回的内容,您还必须处理。

此外,如果客户端在队列关闭后继续调用Pop(),您还需要检查队列之前是否关闭过,而不是进入等待状态,而是提前返回。

一般sync.Cond文档不足,它与其他 Go 同步模式(例如 select)不兼容,许多人不认为它是 Go 中有用的同步原语,并且可能会在 Go 2 中删除, 请参阅 details .

可以使用 channel 代替 sync.Cond,例如关闭 channel 对应于Cond.Broadcast(),在 channel 上发送一个值对应于Cond.Signal()

回到你的例子。最简单的并发安全队列本身就是一个缓冲 channel 。推送操作是一个send在 channel 上,pop 操作是一个 receive从 channel 。 channel 可以安全地同时使用。

缓冲 channel “不知道”的一件事是它具有固定的缓冲区大小,并且一旦创建,缓冲区大小就无法更改。不过,我认为事先分配一个大缓冲区并且以后不用担心任何事情是一个很小的代价。在缓冲区已满的 channel 上发送不会 panic ,“只是”阻塞,直到有人从 channel 接收。

关于go - 如何停止所有等待 sync.Cond 的 goroutines?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62791341/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com