9 cgo

下面是一个使用cgo的例子:

  1. package rand
  2. /*
  3. #include <stdlib.h>
  4. */
  5. import "C"
  6. func Random() int {
  7. return int(C.random())
  8. }
  9. func Seed(i int) {
  10. C.srandom(C.uint(i))
  11. }

rand包导入了”C”,但是在Go的标准库中并没有一个”C”包。这是因为”C”是一个伪包,这是一个特殊的名字,cgo通过这个包知道它是引用C命名空间的。Go编译器使用符号”·”来区分命名空间,而C编译器使用不同的约定,因此使用C包中的名字时,Go编译器就知道应该使用C的命名约定。

在将要进入这一章之前,请读者先思考下面一些问题:

  1. Go使用的是分段栈,初始栈大小很小,当发现栈不够时会动态增长。动态增长是通过进入函数时插入检测指令实现的。然而C函数不使用分段栈技术,并且假设栈是足够大的。那么Go是如何处理不让cgo调用发生栈溢出的呢?

  2. Go中的goroutine都是协作式的,运行到调用runtime库时就有机会进行调度。然而C函数是不会与Go的runtime做这种交互的,所以cgo的函数不是一个协作式的,那么如何避免进入C函数的这个goroutine“失控”?

  3. cgo不仅仅是从Go调用C,还包括从C中调用Go函数。这里面又有哪些技术难点?举个简单的例子,C中调用Go函数f,而f中是使用了go建立新的goroutine的,但是在C中是不支持Go的runtime的。