C回调和非Go线程

Mat*_*ner 10 c gcc callback go

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

Update0

  • 我不想使用SWIG.
  • 回调将来自线程Go以前没有见过.既没有cgo/life也没有任何pkg/runtime证据表明这种行为是AFAICT.

rog*_*rog 5

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

我创建了一个提供此功能的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
Run Code Online (Sandbox Code Playgroud)

试试第二个例子:

goinstall rog-go.googlecode.com/hg/exp/example/event
cd $GOROOT/src/pkg/rog-go.googlecode.com/hg/exp/example/event
gotest
Run Code Online (Sandbox Code Playgroud)

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

以下是回调包的文档:

包

package callback
import "rog-go.googlecode.com/hg/exp/callback"
Run Code Online (Sandbox Code Playgroud)

变量

var Func = callbackFunc
Run Code Online (Sandbox Code Playgroud)

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)
}
Run Code Online (Sandbox Code Playgroud)


cth*_*m06 4

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

\n\n

IIRC,这要么无法完成,要么无法使用 6g+cgo 和朋友轻松完成。Go 使用不同的调用约定(以及分段堆栈等)。

\n\n

但是,您可以为 [685]c (甚至 [685]a)编写 C 代码,并使用 package\xc2\xb7function() 轻松调用 go (您甚至可以调用方法 IIRC)。查看包的来源runtime。

\n\n

更新:

\n\n

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

\n\n

诚然,这是一个黑客行为;我还没有仔细观察过,但可能需要一些其他的技巧才能让它工作(我相信通道本身维护着一个正在等待它们的 goroutine 列表 [编辑:确认:] runtime\xc2\xb7ready(gp);,所以你\'你的 go 代码中需要一些东西来唤醒接收通道或保证 go 代码不会在通道上接收,直到你已经推送了一个值)。然而,我看不出有任何理由这不能工作,而在 C 中创建的线程上运行 6g 生成的代码却有明确的原因。

\n\n

不过,我最初的答案仍然成立:除非添加语言或运行时,否则这还不能按照您想要的方式完成(我很乐意在这里被证明是错误的)。

\n