golang 如何给Mutex添加一个TryLock
以下是Mutex的结构体:
type Mutex struct {
state int32
sema uint32
}
其中state字段用来表示这个Mutex的状态,即是否被锁:
0 表示未锁,二进制表示为 0000
1 表示已锁住,二进制表示为 0001
2 表示已唤醒,二进制表示为 0010
4 表示饥饿,二进制表示为 0100
package main
import (
"fmt"
"sync"
"sync/atomic"
"time"
"unsafe"
)
// 复制Mutex定义的常量
const (
mutexLocked = 1 << iota // 加锁标识位置
mutexWoken // 唤醒标识位置
mutexStarving // 锁饥饿标识位置
mutexWaiterShift = iota // 标识waiter的起始bit位置
)
// 扩展一个Mutex结构
type Mutex struct {
sync.Mutex
}
func main() {
var mu Mutex
go func() { // 启动一个goroutine持有一段时间的锁
mu.Lock()
time.Sleep(6 * time.Second)
mu.Unlock()
}()
time.Sleep(time.Second)
ok := mu.TryLock() // 尝试获取到锁
// 获取成功
if ok {
fmt.Println("got the lock")
// do something
mu.Unlock()
}
return
// 没有获取到
}
// 尝试获取锁
func (m *Mutex) TryLock() bool {
// 如果能成功抢到锁
if atomic.CompareAndSwapInt32((*int32)(unsafe.Pointer(&m.Mutex)), 0, mutexLocked) {
return true
}
// 如果处于唤醒、加锁或者饥饿状态,这次请求就不参与竞争了,返回false
old := atomic.LoadInt32((*int32)(unsafe.Pointer(&m.Mutex)))
if old&(mutexLocked|mutexStarving|mutexWoken) != 0 {
return false
}
// 尝试在竞争的状态下请求锁
new := old | mutexLocked
return atomic.CompareAndSwapInt32((*int32)(unsafe.Pointer(&m.Mutex)), old, new)
}