文档章节

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

天朝搬砖工
 天朝搬砖工
发布于 2015/12/29 16:57
字数 595
阅读 224
收藏 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
使用 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
Windows 下GCC编译C程序调用Golang静态库和C动态库

编译golang 静态库 package main import ( "C" "fmt") //export Foofunc Foo(a, b int) int { return a + b} //export Barfunc Bar() { fmt.Println("Hello, I'm LiLei.")} func main() { }......

hotkit
02/06
0
0
Ruby vs Golang:四个维度对比,谁更胜一筹?

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

局长
08/15
0
11
golang基础-防忘指北

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

GameKing
2016/03/19
114
0

没有更多内容

加载失败,请刷新页面

加载更多

mixin混入

①新建mixin.js文件 const mixin = { methods: { /** * 分页公共方法 */ handleSizeChange(val) { this.pageData.size = val; this.query(); }, hand......

不负好时光
6分钟前
0
0
ERC1155实践|区块链游戏的平行宇宙和为此而生的Enjin钱包

1 摘要 恩金(Enjin)花了大半年的时间一直在完善ERC-1155这个通证协议,毫不夸张地说,该标准是现有以太坊上最适用于游戏资产的通证标准,将主流游戏中道具涉及到的一切操作经过高度抽象之后...

HiBlock
53分钟前
1
0
Oracle发布开源的轻量级 Java 微服务框架 Helidon

近日,Oracle推出了一个新的开源框架Helidon,该项目是一个用于创建基于微服务的应用程序的Java库集合。和Payara Micro、Thorntail(之前的WildFly Swarm)、OpenLiberty、TomEE等项目一样,...

关注公众号_搜云库_每天更新
59分钟前
1
0
启动线程以及安全终止线程

启动 使用start()方法可以启动线程。 start()方法的含义是告知线程规划器线程已初始化完毕,可以分给这个线程时间片了(执行run()方法)。 安全终止线程 示例代码 import java.util.concurr...

karma123
今天
1
0
Python+OpenCV 图像风格迁移(模仿名画)

现在很多人都喜欢拍照(自拍)。有限的滤镜和装饰玩多了也会腻,所以就有 APP 提供了模仿名画风格的功能,比如 prisma、versa 等,可以把你的照片变成 梵高、毕加索、蒙克 等大师的风格。 这...

crossin
今天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部