如何在cgo中复用共享库变量?Go生成so内存共享异常排查
问题原因
你误解了共享库的“共享”含义:Go编译的c-shared共享库仅实现代码段在多进程间复用,但每个进程加载共享库时,会为库中的全局变量创建独立的私有数据副本。也就是说,cgo1进程里初始化的globalConfig只存在于它自己的地址空间,cgo2进程加载同一个so后,会得到一个全新的、未初始化的globalConfig副本,自然输出空值。
解决方案:用系统级共享内存实现跨进程变量复用
要让多个进程共享同一份变量数据,必须依赖操作系统提供的跨进程共享内存机制(比如Linux的System V共享内存、mmap匿名共享内存等)。下面是基于Linux System V共享内存改造后的示例:
修改后的共享库代码(main.go)
package main import "C" import ( "fmt" "os" "os/signal" "syscall" "time" "unsafe" ) // 定义共享内存的标识key和存储大小 const ( shmKey = 0x12345678 shmSize = 256 // 足够存储目标字符串的大小 ) var ( globalConfig string shmAddr unsafe.Pointer ) func main() {} //export search func search() { if shmAddr == nil { // 挂载已存在的共享内存 id, err := syscall.Shmget(shmKey, shmSize, 0666) if err != nil { fmt.Println("shmget error:", err) return } addr, err := syscall.Shmat(id, nil, 0) if err != nil { fmt.Println("shmat error:", err) return } shmAddr = addr } // 从共享内存读取字符串 sharedStr := (*[shmSize]byte)(shmAddr) fmt.Println(string(sharedStr[:])) } //export start func start() { // 创建或获取共享内存(不存在则创建) id, err := syscall.Shmget(shmKey, shmSize, 0666|syscall.IPC_CREAT) if err != nil { fmt.Println("shmget error:", err) return } // 挂载共享内存到当前进程地址空间 addr, err := syscall.Shmat(id, nil, 0) if err != nil { fmt.Println("shmat error:", err) return } shmAddr = addr // 将全局变量写入共享内存 globalConfig = "global value" copy((*[shmSize]byte)(addr)[:], globalConfig) // 保持进程运行 go forever() quitChannel := make(chan os.Signal, 1) signal.Notify(quitChannel, syscall.SIGINT, syscall.SIGTERM) <-quitChannel // 进程退出时清理共享内存(可选,若需长期共享可删除此步骤) syscall.Shmdt(shmAddr) syscall.Shctl(id, syscall.IPC_RMID, nil) } func forever() { for { time.Sleep(10 * time.Second) fmt.Println(globalConfig) } }
编译和运行步骤
- 重新编译共享库:
go build -buildmode=c-shared -o libsdk.so main.go
- 先启动cgo1.go(初始化共享内存):
go run cgo1.go
- 另开终端启动cgo2.go:
go run cgo2.go
此时cgo2会输出global value,实现了跨进程的变量复用。
额外说明
- 共享内存是系统级资源,需注意生命周期管理:如果
start函数退出时执行了IPC_RMID,其他进程将无法再访问该共享内存;若需要长期共享,可以去掉清理步骤,后续手动用ipcrm命令删除。 - 除了System V共享内存,也可以用
mmap映射文件实现共享,或者用Unix域套接字、Redis等中间件实现进程间数据共享,可根据实际场景选择。
内容的提问来源于stack exchange,提问作者Pandy Yang
相关产品推荐
相关产品推荐

