65 lines
1.6 KiB
Go
65 lines
1.6 KiB
Go
// bulma/atomic_stack.go
|
||
package main
|
||
|
||
import (
|
||
"fmt"
|
||
"sync/atomic"
|
||
)
|
||
|
||
// StackNode 无锁栈节点(泛型,支持任意数据类型)
|
||
type StackNode[T any] struct {
|
||
Value T
|
||
Next *StackNode[T] // 指向栈底节点
|
||
}
|
||
|
||
// LockFreeStack 无锁栈(基于atomic.Pointer实现)
|
||
type LockFreeStack[T any] struct {
|
||
head atomic.Pointer[StackNode[T]] // 栈顶指针(原子指针)
|
||
}
|
||
|
||
// Push 入栈:通过CAS操作替换栈顶,保证并发安全
|
||
func (s *LockFreeStack[T]) Push(val T) {
|
||
for {
|
||
oldHead := s.head.Load()
|
||
newHead := &StackNode[T]{Value: val, Next: oldHead}
|
||
// CAS操作成功则入栈完成,失败则重试(避免并发冲突)
|
||
if s.head.CompareAndSwap(oldHead, newHead) {
|
||
return // CAS 成功,退出
|
||
}
|
||
// CAS 失败(被其他 goroutine 修改),重试
|
||
}
|
||
}
|
||
|
||
// Pop 出栈:通过CAS操作替换栈顶为下一个节点,无元素时返回false
|
||
func (s *LockFreeStack[T]) Pop() (T, bool) {
|
||
for {
|
||
oldHead := s.head.Load()
|
||
if oldHead == nil {
|
||
var zero T // 空值,对应泛型默认零值
|
||
return zero, false
|
||
}
|
||
// CAS操作成功则出栈完成,返回栈顶元素
|
||
if s.head.CompareAndSwap(oldHead, oldHead.Next) {
|
||
return oldHead.Value, true
|
||
}
|
||
}
|
||
}
|
||
|
||
func main() {
|
||
stack := &LockFreeStack[int]{}
|
||
// 入栈3个元素(10、20、30)
|
||
stack.Push(10)
|
||
stack.Push(20)
|
||
stack.Push(30)
|
||
// 出栈(LIFO:后进先出,依次弹出30、20、10)
|
||
for i := 0; i < 3; i++ {
|
||
if val, ok := stack.Pop(); ok {
|
||
fmt.Printf("✅ 弹出: %d\n", val)
|
||
}
|
||
}
|
||
// 空栈测试:弹出操作失败
|
||
if _, ok := stack.Pop(); !ok {
|
||
fmt.Println("栈已为空,弹出失败")
|
||
}
|
||
}
|