123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566 |
- // Package mhayaQueue provides an efficient implementation of a multi-producer, single-consumer lock-free queue.
- //
- // The Push function is safe to call from multiple goroutines. The pop and Empty APIs must only be
- // called from a single, consumer goroutine.
- package mhayaQueue
- // This implementation is based on http://www.1024cores.net/home/lock-free-algorithms/queues/non-intrusive-mpsc-node-based-queue
- import (
- "sync/atomic"
- "unsafe"
- )
- type node struct {
- next *node
- val interface{}
- }
- type Queue struct {
- head, tail *node
- }
- func NewQueue() Queue {
- q := Queue{}
- stub := &node{}
- q.head = stub
- q.tail = stub
- return q
- }
- // Push adds x to the back of the queue.
- //
- // Push can be safely called from multiple goroutines
- func (q *Queue) Push(x interface{}) {
- n := new(node)
- n.val = x
- // current producer acquires head node
- prev := (*node)(atomic.SwapPointer((*unsafe.Pointer)(unsafe.Pointer(&q.head)), unsafe.Pointer(n)))
- // release node to consumer
- atomic.StorePointer((*unsafe.Pointer)(unsafe.Pointer(&prev.next)), unsafe.Pointer(n))
- }
- // Pop removes the item from the front of the queue or nil if the queue is empty
- //
- // Pop must be called from a single, consumer goroutine
- func (q *Queue) Pop() interface{} {
- tail := q.tail
- next := (*node)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&tail.next)))) // acquire
- if next != nil {
- q.tail = next
- v := next.val
- next.val = nil
- return v
- }
- return nil
- }
- // Empty returns true if the queue is empty
- //
- // must be called from a single, consumer goroutine
- func (q *Queue) Empty() bool {
- tail := q.tail
- next := (*node)(atomic.LoadPointer((*unsafe.Pointer)(unsafe.Pointer(&tail.next))))
- return next == nil
- }
|