我写了一个队列类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()调用者将被阻塞。有什么方法可以停止等待Pop()被任何 Cond 调用阻塞的所有例程?当然我可以做类似的事情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冗长的情况下停止等待?
1 回答
牛魔王的故事
TA贡献1830条经验 获得超3个赞
您可以使用 唤醒所有等待的客户端Pop()
,但是如果为空并且没有任何内容可返回Cond.Broadcast()
,您还必须处理。q.data
此外,如果队列关闭后客户端继续调用Pop()
,您还需要检查队列之前是否已关闭,并且不进入等待状态而是提前返回。
通常sync.Cond
文档不足,它与其他 Go 同步模式(例如select
)不兼容,并且许多人认为它不是 Go 中有用的同步原语,并且可能会在 Go 2 中被删除,请参阅详细信息。
可以使用通道来代替sync.Cond
,例如关闭对应的通道,在对应Cond.Broadcast()
的通道上发送一个值Cond.Signal()
。
回到你的例子。最简单的并发安全队列本身就是一个缓冲通道。推操作是在通道上发送,弹出操作是从通道接收。通道对于并发使用是安全的。
缓冲通道“不知道”的一件事是它具有固定的缓冲区大小,并且一旦创建,缓冲区大小就无法更改。尽管如此,我认为事先分配一个大缓冲区而不用担心以后的任何事情是一个很小的代价。在缓冲区已满的通道上发送不会恐慌“只是”阻塞,直到有人从通道接收。
- 1 回答
- 0 关注
- 94 浏览
添加回答
举报
0/150
提交
取消