C调用Golang动态库时的坑与个人解决方法
C调用Golang动态库时的坑与个人解决方法
WangRichard 发表于2年前
C调用Golang动态库时的坑与个人解决方法
  • 发表于 2年前
  • 阅读 144
  • 收藏 2
  • 点赞 0
  • 评论 0

腾讯云 新注册用户 域名抢购1元起>>>   

      项目需求,复用了一段之前写过的Go代码,利用Go 1.5的新功能导出了一个可以给C语言使用的动态库。由于目前Go的结构体还不支持直接导出到C,因此使用了interface{}作为过渡。结构体以及导出函数定义如下

type Handler struct{
    stream *Stream
    p      *Parser
}

//export NewHandler
func NewHandler() interface{}{
    return Handler{
      //成员变量初始化
    }
}

//export Func1
func Func1(handler interface{}){
  if h, ok := handler.(Handler);ok{
      //访问stream成员
      foo1(h.stream)
  }
}

//export Func2
func Func2(handler interface{}){
  if h, ok := handler.(Handler);ok{
      //访问stream成员
      foo2(h.stream)
  }
}

      按照如上写法,在C代码中依次调用,在执行Func1时还算ok,但是在执行到Func2时,则报了h.stream内存地址非法的错误,暂时还不明白stream在哪被gc了,还望各位赐教。

      另外,如下代码则没问题。

//export NewHandler
func NewHandler() interface{}{
    return &Handler{
      //成员变量初始化
    }
}

//export Func1
func Func1(handler interface{}){
  if h, ok := handler.(*Handler);ok{
      //访问stream成员
      foo1(h.stream)
  }
}

//export Func2
func Func2(handler interface{}){
  if h, ok := handler.(*Handler);ok{
      //访问stream成员
      foo2(h.stream)
  }
}

更新1: 2015.12.30 测试结果表明,改为指针也不能有效解决该问题,仍然会出现内存地址非法情况,看来是Go里面的对象导出给C使用后,gc对该对象的跟踪出了问题,导致在C里边还在使用该对象时却被Go里边回收了。

更新2: 由于是被Go内部gc,考虑在Go代码增加一对象池防止对象被gc,另外考虑到给不熟悉Go的使用C的童鞋,此处返回unsafe.Pointer代替之前的interface{},更改后的逻辑如下

var(
 	obj_pool = map[unsafe.Pointer]*Handler{}
	lock     = make(chan bool, 1)
)

type Handler struct{
    stream *Stream
    p      *Parser
}

//export NewHandler
func NewHandler() unsafe.Pointer{
    p:= &Handler{
      //成员变量初始化
    }
    lock <- true
    defer func() { <-lock }()
    obj_pool[unsafe.Pointer(p)] = p
    return unsafe.Pointer(p)    
}

//其他导出函数...
//......

//export ReleaseHandler
func ReleaseHandler(handler unsafe.Pointer){
     lock <- true
     defer func() { <-lock }()
     if _, ok := obj_pool[handler]; ok {
	 delete(obj_pool, handler)
     }
}

      增加对象池后,之前的Go导出对象被gc的问题基本上已经没看到了,相当于变相在Go里面增加对象引用以防止被gc。此外,为了防止资源泄露,采用对象池的方法处理后,自然需要添加一个释放对象的逻辑,于是增加ReleaseHandler方法。

标签: Golang C 动态库
共有 人打赏支持
粉丝 5
博文 9
码字总数 10668
×
WangRichard
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: