github.com/rolandhe/saber@v0.0.4/gocc/defaultBlockingqueue.go (about)

     1  // Golang concurrent tools like java juc.
     2  //
     3  // Copyright 2023 The saber Authors. All rights reserved.
     4  //
     5  
     6  package gocc
     7  
     8  import (
     9  	"time"
    10  )
    11  
    12  const defaultLimit = 128
    13  
    14  // NewDefaultBlockingQueue 构建一个有界队列,缺省的队列底层使用channel
    15  //
    16  //	limit 队列容量
    17  func NewDefaultBlockingQueue[T any](limit int64) BlockingQueue[T] {
    18  	if limit < 0 {
    19  		limit = defaultLimit
    20  	}
    21  	return &chanBlockingQueue[T]{
    22  		make(chan *Elem[T], limit),
    23  	}
    24  }
    25  
    26  // Elem 进入队列的元素使用Elem来封装
    27  type Elem[T any] struct {
    28  	v *T
    29  }
    30  
    31  // GetValue 获取Elem内封装的数据
    32  func (el *Elem[T]) GetValue() T {
    33  	return *(el.v)
    34  }
    35  
    36  // BlockingQueue 线程安全地有界队列, 支持阻塞offer/pull, 超时offer/pull,立即offer/pull
    37  type BlockingQueue[T any] interface {
    38  	// Offer 写入队列,如果队列已满,等待,直到写入位置
    39  	Offer(t T)
    40  	// TryOffer 尝试写入队列,如果当前队列已满,立即返回false,如果能够写入,返回true
    41  	TryOffer(t T) bool
    42  	// OfferTimeout 超时写入,等待时间内写入返回true,否则返回false
    43  	OfferTimeout(t T, timeout time.Duration) bool
    44  	// Pull 与Offer相反, 从队列读取数据,如果队列为空,阻塞,直至有数据位置
    45  	Pull() *Elem[T]
    46  	// TryPull 尝试读取数据,如果队列有数据直接返回,如果队列为空,返回false
    47  	TryPull() (*Elem[T], bool)
    48  	// PullTimeout 超时读取,等待时间内读取到数据返回true,否则返回false
    49  	PullTimeout(timeout time.Duration) (*Elem[T], bool)
    50  }
    51  
    52  // 基于golang channel实现,构建buffered channel,利用channel的并发安全能力来实现并发队列,
    53  // channel是不能被close的,所以应用是推荐使用TryOffer/TryPull和超时方法
    54  type chanBlockingQueue[T any] struct {
    55  	q chan *Elem[T]
    56  }
    57  
    58  func (ci *chanBlockingQueue[T]) Offer(t T) {
    59  	ci.q <- &Elem[T]{&t}
    60  }
    61  
    62  func (ci *chanBlockingQueue[T]) TryOffer(t T) bool {
    63  	select {
    64  	case ci.q <- &Elem[T]{&t}:
    65  		return true
    66  	default:
    67  		return false
    68  	}
    69  }
    70  
    71  func (ci *chanBlockingQueue[T]) OfferTimeout(t T, timeout time.Duration) bool {
    72  	select {
    73  	case ci.q <- &Elem[T]{&t}:
    74  		return true
    75  	case <-time.After(timeout):
    76  		return false
    77  	}
    78  }
    79  
    80  func (ci *chanBlockingQueue[T]) Pull() *Elem[T] {
    81  	v := <-ci.q
    82  	return v
    83  }
    84  
    85  func (ci *chanBlockingQueue[T]) TryPull() (*Elem[T], bool) {
    86  	select {
    87  	case v := <-ci.q:
    88  		return v, true
    89  	default:
    90  		return nil, false
    91  	}
    92  }
    93  func (ci *chanBlockingQueue[T]) PullTimeout(timeout time.Duration) (*Elem[T], bool) {
    94  	select {
    95  	case v := <-ci.q:
    96  		return v, true
    97  	case <-time.After(timeout):
    98  		return nil, false
    99  	}
   100  }