github.com/bruceshao/lockfree@v1.1.3-0.20230816090528-e89824c0a6e9/consumer.go (about)

     1  /*
     2   * Copyright (C) THL A29 Limited, a Tencent company. All rights reserved.
     3   *
     4   * SPDX-License-Identifier: Apache-2.0
     5   *
     6   */
     7  
     8  package lockfree
     9  
    10  import (
    11  	"fmt"
    12  	"runtime"
    13  	"sync/atomic"
    14  )
    15  
    16  // consumer 消费者,这个消费者只会有一个g操作,这样处理的好处是可以不涉及并发操作,其内部不会涉及到任何锁
    17  // 对于实际的并发操作由该g进行分配
    18  type consumer[T any] struct {
    19  	status int32 // 运行状态
    20  	rbuf   *ringBuffer[T]
    21  	seqer  *sequencer
    22  	blocks blockStrategy
    23  	hdl    EventHandler[T]
    24  }
    25  
    26  func newConsumer[T any](rbuf *ringBuffer[T], hdl EventHandler[T], sequer *sequencer, blocks blockStrategy) *consumer[T] {
    27  	return &consumer[T]{
    28  		rbuf:   rbuf,
    29  		seqer:  sequer,
    30  		hdl:    hdl,
    31  		blocks: blocks,
    32  		status: READY,
    33  	}
    34  }
    35  
    36  func (c *consumer[T]) start() error {
    37  	if atomic.CompareAndSwapInt32(&c.status, READY, RUNNING) {
    38  		go c.handle()
    39  		return nil
    40  	}
    41  	return fmt.Errorf(StartErrorFormat, "Consumer")
    42  }
    43  
    44  func (c *consumer[T]) handle() {
    45  	// 判断是否可以获取到
    46  	rc := c.seqer.nextRead()
    47  	for {
    48  		if c.closed() {
    49  			return
    50  		}
    51  		var i = 0
    52  		for {
    53  			if c.closed() {
    54  				return
    55  			}
    56  			// 看下读取位置的seq是否OK
    57  			if v, p, exist := c.rbuf.contains(rc - 1); exist {
    58  				rc = c.seqer.readIncrement()
    59  				c.hdl.OnEvent(v)
    60  				i = 0
    61  				break
    62  			} else {
    63  				if i < spin {
    64  					procyield(30)
    65  				} else if i < spin+passiveSpin {
    66  					runtime.Gosched()
    67  				} else {
    68  					c.blocks.block(p, rc)
    69  					i = 0
    70  				}
    71  				i++
    72  			}
    73  		}
    74  	}
    75  }
    76  
    77  func (c *consumer[T]) close() error {
    78  	if atomic.CompareAndSwapInt32(&c.status, RUNNING, READY) {
    79  		// 防止阻塞无法释放
    80  		c.blocks.release()
    81  		return nil
    82  	}
    83  	return fmt.Errorf(CloseErrorFormat, "Consumer")
    84  }
    85  
    86  // closed 判断是否已关闭
    87  // 将直接判断调整为原子操作,解决data race问题
    88  func (c *consumer[T]) closed() bool {
    89  	return atomic.LoadInt32(&c.status) == READY
    90  }