github.com/tursom/GoCollections@v0.3.10/concurrent/lock/CLH.go (about)

     1  package lock
     2  
     3  import (
     4  	"github.com/petermattis/goid"
     5  
     6  	"github.com/tursom/GoCollections/exceptions"
     7  	"github.com/tursom/GoCollections/lang/atomic"
     8  )
     9  
    10  type (
    11  	CLH struct {
    12  		tail  atomic.Reference[clhNode]
    13  		state atomic.Reference[clhNode]
    14  	}
    15  
    16  	clhNode struct {
    17  		prev   *clhNode
    18  		locked atomic.Bool
    19  		gid    int64
    20  	}
    21  )
    22  
    23  func (c *CLH) Lock() {
    24  	node := &clhNode{
    25  		prev:   c.tail.Load(),
    26  		locked: 1, // true
    27  		gid:    goid.Get(),
    28  	}
    29  
    30  	for !c.tail.CompareAndSwap(node.prev, node) {
    31  		node.prev = c.tail.Load()
    32  	}
    33  
    34  	if node.prev == nil {
    35  		return
    36  	}
    37  
    38  	for node.prev.locked.Load() {
    39  	}
    40  
    41  	c.state.Store(node)
    42  }
    43  
    44  func (c *CLH) Unlock() {
    45  	node := c.state.Load()
    46  	if node.gid != goid.Get() {
    47  		panic(exceptions.NewIllegalAccessException("unlock with wrong goroutine", nil))
    48  	}
    49  
    50  	node.locked.Store(false)
    51  }