先看要用到的知识点
总结相关的问题知识点(简要说明,自己找资料学):
1.golang 的 struct 字段的内存存储
struct 的字段内容是否连续,如何读取,这个问题关系到unsafe获取内存的内容情况,因为语言层面的类型是不一样的
2内存对齐以及cpu的块读取
struct 字段之间存在偏移量,针对cpu的块读取能提高效率,以及对应上面的问题进行拓展,不同类型在同一个struct的unsafe读取是怎么样的
3.cpu 大小端
它指的是:一种是将低序字节存储在起始地址,这称为小端(little-endian)字节序;另一种方法是将高序字节存储在起始地址,这称为大端(big-endian)字节序。简单的来说大概就是白话文的读取顺序和古文顺序不同,这里对应机器读取和人为读取习惯。对应unsafe 读取不同类型可能出现极大值的现象(int64读取)
4 golang unsafe.Pointer 原文地址
Package unsafe contains operations that step around the type safety of Go programs.
// unsafe 的操作绕过 Go 的安全机制
Packages that import unsafe may be non-portable and are not protected by the Go 1 compatibility guidelines.
// unsafe 不遵从 Go1的原则,就是说不保证向前兼容
直接一点的说,他的作用是什么呢,就是直接获取内存里面的的东西。结合最开始的代码来解释一下;
old := atomic.LoadInt32((*int32)(unsafe.Pointer(&m.Mutex)))
1. unsafe.Pointer 获取了 m.Mutex 的地址内存内容
2. 转化成 int32 (就是用语言层面的类型约束显示)
3. atomic.LoadInt32 原子包安全的读取
一:问题开始 unsafe 对于锁的使用
先来看一段代码
type Mutex struct {
sync.Mutex
}
func (m *Mutex) TryLock() bool {
if atomic.CompareAndSwapInt32((*int32)(unsafe.Pointer(&m.Mutex)), 0, mutexLocked) {
return true
}
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)
}
今天在研究go底层协程实现的时候,看到锁的过程,然后又找了一些资料,发现好多这么写(包括源码中),获取锁的状态,感觉很有意思,记录一下
首先说明 sync.Mutex 的内部结构
type Mutex struct {
state int32
sema uint32
}
如上所示,state 代表了状态(0,1)是否上锁,sema是记录是否有饥饿状态,队列等待等。现在看来,上述 unsafe 的操作是直接获取了state 的内容,而且该字段是一个私有字段。这里依赖来了 unsafe 的特殊指针。因为 golang 弱化了指针的使用,而且不允许指针运算,但你硬要用怎么办呢,就用 unsafe 这个包了。
网友评论