C回调和非Go线程

  1. 如何从不是由Go创建的线程调用C中的Go代码?
  2. 我分配给C函数指针,以便Go不创建的线程可以调用该指针并进入Go代码?

Update0

  • 我不想使用SWIG。
  • 回调将来自线程Go以前没有见过。 cgo/lifepkg/runtime任何内容都不会显示此行为AFAICT。

你可以这样做,但解决方案相对较慢(我的机器每次呼叫约22μs)。 答案是C代码使用C线程原语与另一个实际运行回调的goroutine进行通信。

我创建了一个提供此function的Go包: rog-go.googlecode.com/hg/exp/callback 。 这里有一个展示其用途的示例包。 该示例演示了从Go运行时外部创建的线程调用任意Go闭包。 另一个例子就在这里 。 这演示了一个典型的C回调接口,并在其上层叠了一个Go回调。

试试第一个例子:

 goinstall rog-go.googlecode.com/hg/exp/example/looper cd $GOROOT/src/pkg/rog-go.googlecode.com/hg/exp/example/looper gotest 

试试第二个例子:

 goinstall rog-go.googlecode.com/hg/exp/example/event cd $GOROOT/src/pkg/rog-go.googlecode.com/hg/exp/example/event gotest 

这两个例子都假设pthreads可用。 当然,在cgo修复之前,这只是一个权宜之计,但是在C回调中调用任意Go闭包的技术即使在那时也适用。

以下是回调包的文档:

 package callback import "rog-go.googlecode.com/hg/exp/callback" 

变量

 var Func = callbackFunc 

Func拥有一个指向C回调函数的指针。 调用时,它在带有给定参数的Go上下文中调用提供的函数f。

它可以通过首先将其转换为函数指针然后从C调用来使用。以下是设置回调函数的示例:

 //static void (*callback)(void (*f)(void*), void *arg); //void setCallback(void *c){ // callback = c; //} import "C" import "rog-go.googlecode.com/hg/exp/callback" func init() { C.setCallback(callback.Func) } 

我假设你的意思是用gcc编译的C代码?

IIRC,无论是使用6g + cgo还是朋友都无法轻松完成或无法轻松完成。 Go使用不同的调用约定(以及分段堆栈等)。

但是,您可以为[685] c(甚至[685] a)编写C代码,并使用package·function()轻松调用(您甚至可以调用方法IIRC)。 有关示例,请参阅runtime包的源代码 。

更新:

更新后回到这个问题,并给它一些更多的想法。 这不能使用6c或cgo以标准方式完成。 特别是因为线程不是由运行时启动的,所以当前的实现会失败。 调度程序突然有一个它不知道的控制线程; 此外,该线程将缺少一些线程局部变量,运行时用于管理堆栈和其他一些东西。 此外,如果go函数返回一个值(或几个),则C代码无法在当前支持的平台上访问它,因为go返回堆栈上的值(您可以使用程序集访问它们)。 考虑到这些因素,我相信您仍然可以使用渠道来做到这一点。 它需要你的C代码与go运行时的内部工作有点过于亲密,但它适用于给定的实现。 虽然使用频道可能不是您正在寻找的解决方案,但它可能更适合Go的概念而不是回调。 如果您的C代码至少重新实现了通道实现中的发送方法(该代码是为6c编写的,那么它最有可能适用于gcc,它调用go运行时,我们已经确定不能从非去线程完成,您应该能够锁定频道并将值推送到它。 go调度程序可以继续管理它自己的线程,但现在它可以从C中启动的其他线程接收数据。

诚然,这是一个黑客; 我看起来还不够近,但它可能需要一些其他的黑客才能使它工作(我相信通道本身会维护一个等待它们的goroutine列表[编辑:确认: runtime·ready(gp); ],所以你需要在你的代码中唤醒接收频道或保证在你已经推送了一个值之前在频道上不会收到的代码。 但是,我看不出有什么理由不起作用,而有明确的理由在C中创建的线程上运行由6g生成的代码不能。

我的原始答案仍然有效: 除了语言或运行时的增加,这还不能按照你想要的方式完成 (我很想在这里被certificate是错的)。

您可以在PortAudio音频I / O库的这些绑定中找到rog的回调包的实际应用程序: http : //code.google.com/p/portaudio-go/ 。 可能会让它更容易理解..

(感谢你的实施,rog。这正是我所需要的!)