文档章节

C调用Golang动态库时的坑与个人解决方法

天朝搬砖工
 天朝搬砖工
发布于 2015/12/29 16:57
字数 595
阅读 267
收藏 2

      项目需求,复用了一段之前写过的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方法。

© 著作权归作者所有

共有 人打赏支持
天朝搬砖工
粉丝 4
博文 14
码字总数 11252
作品 0
东城
其他
私信 提问
golang的调用shell的库--go-sh

go-sh是一个golang的调用shell的库。 使用linux的人都知道shell脚本有它难以取代的优势,用2个词形容就是,简单、粗暴。但是shell有不少的坑,很容易就写的换个机器就不能使了。golang的优势...

go-skyblue
2014/02/09
4K
3
Ruby vs Golang:四个维度对比,谁更胜一筹?

软件应用程序的快速增长已经不再只是一件其本身受欢迎的事情了,它更是带来了深刻改善所有行业业务流程的真正机会。所以,对于企业、行业来说,通过合适的编程创建出出色的软件解决方案成为了...

局长
08/15
4.1K
21
使用 golang 实现类似 pthread_barrier_t 语义的 barrier 对象

看到golang标准库sync package WaitGroup 类型, 本以为是golang 版本的 barrier 对象实现,看到文档给出的使用示例: var wg sync.WaitGroup var urls = []string{ "http://www.golang.org/"...

yujian0231
2015/01/18
0
0
golang基础-防忘指北

一 坑 1. 用自带的 json 库序列化 strut 变量时,只有那些首字母大写的变量才会被序列化,这意味着在go的世界里,所有的json属性名都是大写开头...这真的不是bug吗...(ps : 已经找到大写转小...

GameKing
2016/03/19
114
0
database/sql: rows.Next panic from concurrent map writes

版权声明:本文为Doctorq原创文章,未经博主允许不得转载。 https://blog.csdn.net/qhshiniba/article/details/82347851 问题描述 我们最近用golang重构了以前c++的系统,在最后上线前的压测...

Q博士
09/03
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Spring源码学习笔记-1-Resource

打算补下基础,学习下Spring源码,参考书籍是《Spring源码深度解析》,使用版本是Spring 3.2.x,本来想试图用脑图记录的,发现代码部分不好贴,还是作罢,这里只大略记录下想法,不写太细了 ...

zypy333
今天
10
0
RestClientUtil和ConfigRestClientUtil区别说明

RestClientUtil directly executes the DSL defined in the code. ConfigRestClientUtil gets the DSL defined in the configuration file by the DSL name and executes it. RestClientUtil......

bboss
今天
17
0

中国龙-扬科
昨天
2
0
Linux系统设置全局的默认网络代理

更改全局配置文件/etc/profile all_proxy="all_proxy=socks://rahowviahva.ml:80/"ftp_proxy="ftp_proxy=http://rahowviahva.ml:80/"http_proxy="http_proxy=http://rahowviahva.ml:80/"......

临江仙卜算子
昨天
10
0
java框架学习日志-6(bean作用域和自动装配)

本章补充bean的作用域和自动装配 bean作用域 之前提到可以用scope来设置单例模式 <bean id="type" class="cn.dota2.tpye.Type" scope="singleton"></bean> 除此之外还有几种用法 singleton:......

白话
昨天
10
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部