场景一:对接C程序
大多数都是用于外部C程序实现的一些高效的库进行叫交互式会用到unsafe
场景二:指针类型转换
“不安全”行为的危险性:go 语言中是不支持强制类型转换的,但是我们使用 unsafe 是可以把一个类型的指针强行转化为任意类型的指针的
package unsafet_test
import (
"fmt"
"sync"
"sync/atomic"
"testing"
"time"
"unsafe"
)
// 不合理转换
func TestUnsafe(t *testing.T) {
i := 10
f := *(*float64)(unsafe.Pointer(&i))
t.Log(unsafe.Pointer(&i))
t.Log(f)
}
// 合理的类型转换
type MyInt int
func TestConvert(t *testing.T) {
a := []int{1, 2, 3, 4}
b := *(*[]MyInt)(unsafe.Pointer(&a))
t.Log(b)
}
// 指针原子类型操作
// 场景:并发读写共享缓存时,为了达到读与写的安全性
// 当写的时候我们写在一个新的内存地址,写完之后用原子操作
// 把读的指针指向新的内存地址
func TestAtomic(t *testing.T) {
var shareBufPtr unsafe.Pointer // 共享内存地址
writeDataFn := func() {
var data []int
for i := 0; i < 100; i++ {
data = append(data, i)
}
//fmt.Println(unsafe.Pointer(&data))
atomic.StorePointer(&shareBufPtr, unsafe.Pointer(&data))
}
readDataFn := func() {
data := atomic.LoadPointer(&shareBufPtr)
fmt.Println(data, *(*[]int)(data))
}
var wg sync.WaitGroup
writeDataFn()
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
for i := 0; i < 10; i++ {
writeDataFn()
time.Sleep(time.Millisecond * 100)
}
wg.Done()
}()
wg.Add(1)
go func() {
for i := 0; i < 10; i++ {
readDataFn()
time.Sleep(time.Millisecond * 100)
}
wg.Done()
}()
}
}
上面代码中的最后一个测试程序,我在 win10 系统中要运行多次才能拿到理想中的结果,好难受啊