将Go指针保持在共享内存中

时间:2018-04-17 21:52:03

标签: go garbage-collection ipc cgo

根据我所做的研究,没有库可以在Go中创建和管理共享内存。我认为使用一些基本的cgo代码可能很容易,事实证明它是。在我前进之前我想要解决的问题涉及Go运行时和Go指向共享内存之间的交互。

为了证明我的顾虑,我创建了一个简单的Go结构

type Test struct {
    X int32
    Y float64
    Z [5]int32
}

我在两个单独的Go程序中公开,A和B以及一些cgo代码。

#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#include <string.h>
int get_mem() {
    key_t key = ftok("shared_mem",65);
    return shmget(key,1024,0666|IPC_CREAT);
}

char * attach_mem(int id) {
    return (char*) shmat(id,(void*)0,0);
}

void detach_mem(char * str) {
    shmdt(str);
}

void destroy_mem(int id) {
    shmctl(id,IPC_RMID,NULL);
}

void write(char * str, char * data, int len) {
    memcpy(str, data, len);
}

程序A然后创建一个Test结构,将其写入共享内存,为该内存创建一个名为*Test的{​​{1}}指针,等待10秒,然后在{{ 1}}。

ptr

在这10秒内,程序B启动,创建一个指向共享内存的ptr指针,并修改其中一个字段。

// Program A
func main() {
    id := C.get_mem()
    str := C.attach_mem(id)
    dataLocal := Test{1, 2.0, [5]int32{3, 4, 5, 6, 7}}
    C.write(str, (*C.char)(unsafe.Pointer(&dataLocal)), C.int(unsafe.Sizeof(dataLocal)))
    ptr := (*Test)(unsafe.Pointer(str))
    time.Sleep(10 * time.Second)
    fmt.Println(ptr)
    C.detach_mem(str)
    C.destroy_mem(id)
}

显然这不是一个实用的IPC实现,但它有效。程序A打印

*Test

我担心的是Go运行时,即垃圾收集器,对这个实现不会很好。具体来说,Go如何处理程序A中的// Program B func main() { id := C.get_mem() str := C.attach_mem(id) data := (*Test)(unsafe.Pointer(str)) data.X = 10 C.detach_mem(str) } ?我知道Go GC会在堆中移动数据,但这是否适用于位于堆外的Go指针引用的数据?既然Go指针引用了这个数据,它会被垃圾收集吗?

如果这些问题都不适用,这种做法是不安全的还是其他方式被认为是不好的风格?如果有的话还有其他替代方案吗?

0 个答案:

没有答案