Files
bulma/atomic_stack.go
T

65 lines
1.6 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 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("栈已为空,弹出失败")
}
}