golang sync mutex 互斥锁 (1)

package main

import (
    "fmt"
    "runtime"
    "sync/atomic"
    "time"
)

type SpinLock struct {
    State uint32
}

func (s *SpinLock) Lock() {
    //cas原子操作 自旋锁
    spin := 1             // 初始自旋次数
    maxSpin := 64         // 最大自旋次数
    blockThreshold := 128 // 自旋次数超过这个阈值,就进入阻塞
    for attempt := 0; ; attempt++ {
        if atomic.CompareAndSwapUint32(&s.State, 0, 1) {
            return
        }
        // 指数退避自旋
        for i := 0; i < spin; i++ {
            runtime.Gosched() // 让出 CPU
        }
        // 增加自旋次数
        if spin < maxSpin {
            // 左移*2
            spin <<= 1
        }
        // 超过阈值,进入阻塞
        if attempt > blockThreshold {
            // 这里短暂休眠,模拟阻塞等待=> 自旋 + 阻塞混合锁通常不是严格公平
            //time.Sleep(time.Microsecond)

            //runtime_Semrelease 阻塞队列

        }
        //当前 G 主动让出 CPU:
        //调度器把它从正在执行的状态摘下来。
        //放回到可运行队列:
        //它会被重新放入 当前 P 的本地队列(runq)。
        //如果本地队列满了,可能会放到 全局队列。
        //M 继续找下一个 G 来执行:
        //M 不会闲着,它会从 P 的本地队列里挑下一个 G 来跑。
        //如果本地没有,就去全局队列或者别的 P 偷任务(work stealing)

        //当前 goroutine 主动停止运行,交还 CPU。
        //调度器会安排 别的 goroutine 上来运行。
        //当前 goroutine 不会消失,只是退回到 可运行队列,等下次被调度器挑中再继续跑

        // runtime.Gosched() 和 time.Sleep() 区别
        //runtime.Gosched()
        //G 仍然在 就绪态,只是重新回到 run queue。
        //很快会被调度回来执行。
        //time.Sleep()
        //G 会进入休眠态,调度器不会把它放到 run queue。
        //直到时间到,才重新进入 run queue。

        //当 goroutine 调用 time.Sleep(d) 时:
        //当前 G 从 M 上摘下来
        //调度器会把正在运行的 goroutine(G)标记为“休眠中”。
        //它不会再占用 CPU。
        //放入 Timer 结构里
        //Go 的 runtime 里有个 timer heap(小根堆),专门用来管理定时器事件。
        //这个 G 会被关联到一个 timer,记录它的唤醒时间(now + d)。
        //调度器切走
        //当前 M 会去执行别的 G(从 P 的 runq 或全局队列里拿)。
        //休眠的 G 不会出现在 runq 里。
        //时间到 → 放回 runq
        //runtime 的 timer 系统会检查堆顶的 timer。
        //当时间到达,就把对应的 G 放回到某个 P 的 runq(本地队列)。
        //调度器就能重新挑它来执行。
    }
}
func (s *SpinLock) UnLock() {
    if atomic.LoadUint32(&s.State) == 0 {
        panic("unlock of unlocked SpinLock")
    }
    atomic.StoreUint32(&s.State, 0)
}

// 尝试上锁
func (s *SpinLock) TryLock() bool {
    return atomic.CompareAndSwapUint32(&s.State, 0, 1)
}

func main() {
    var s SpinLock
    go func() {
        s.Lock()
        fmt.Println("g1 locked")
        time.Sleep(200 * time.Millisecond)
        s.UnLock()
        fmt.Println("g1 unlocked")
    }()
    time.Sleep(50 * time.Millisecond)
    if s.TryLock() {
        fmt.Println("main got lock")
        s.UnLock()
    } else {
        fmt.Println("main failed to get lock")
    }
    time.Sleep(300 * time.Millisecond)
}

评论

(= ̄ω ̄=)··· 暂无内容!

回复

邮箱