C回调和非Go线程 如何从非Go创建的线程调用C中的Go代码 我应该为C函数指针分配什么,这样非Go创建的线程可以调用该指针并输入Go代码 更新0 我不想用SWIG 回调将来自Go以前从未见过的线程。无论是cgo/life还是pkg/runtime中的任何内容都没有演示这种行为

C回调和非Go线程 如何从非Go创建的线程调用C中的Go代码 我应该为C函数指针分配什么,这样非Go创建的线程可以调用该指针并输入Go代码 更新0 我不想用SWIG 回调将来自Go以前从未见过的线程。无论是cgo/life还是pkg/runtime中的任何内容都没有演示这种行为,c,gcc,callback,go,C,Gcc,Callback,Go,我假设您是指使用gcc编译的C代码 IIRC,这不是用6g+cgo和friends做不到,就是不容易做到。Go使用不同的调用约定(以及分段堆栈等) 但是,您可以为[685]C(甚至[685]a)编写C代码,并使用package·function()轻松调用go(您甚至可以调用方法IIRC)。有关示例,请参见 更新: 更新后回到这个问题,并对其进行更多思考。使用6c或cgo无法以标准方式完成此操作。特别是因为线程不是由go运行时启动的,所以当前的实现将失败。调度程序会突然控制一个它不知道的线程;此

我假设您是指使用gcc编译的C代码

IIRC,这不是用6g+cgo和friends做不到,就是不容易做到。Go使用不同的调用约定(以及分段堆栈等)

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

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

诚然,这是一种黑客行为;我看得不够仔细,但可能还需要一些其他的技巧才能让它正常工作(我相信频道本身有一个等待它们的goroutine列表[编辑:确认:
runtime·ready(gp);
],因此您需要go代码中的某些内容来唤醒接收频道,或保证go代码在您推送值之前不会在频道上接收)。然而,我看不出有什么原因这不能工作,而有一些明确的原因是在C中创建的线程上运行6g生成的代码不能工作


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

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

我创建了一个Go包,该包提供以下功能:。 有一个示例包演示了它的使用。该示例演示了从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
这两个示例都假设pthread可用。当然,在cgo被修复之前,这只是一个权宜之计,但是在C回调中调用任意Go闭包的技术即使在那时也是适用的

以下是回调包的文档:

套餐

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

var Func = callbackFunc
Func持有指向C回调函数的指针。 调用时,它调用 具有给定参数的Go上下文

它可以通过首先将其转换为函数指针来使用 然后从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)
}

您可以在PortAudio音频I/O库的以下绑定中找到rog回调包的实际应用程序:。可能更容易理解


(谢谢你实现了这一点,罗格。这正是我所需要的!)

哦,等等,你在发疯名单上,而你就是几个小时前刚刚问这个问题的人。@Matt Kane:尽我所能提高golang的可视性和文档记录,它处于最底层。我用一个想法更新了我的答案,但我仍然不相信这是可以做到的。嗯,我在你更新之前写了我的答案,当时SWIG并没有被禁止。事实上,你的更新增加了很多当时没有的细节。接受赏金毫无意义有人接受赏金吗?“所有这些用户中只有2个Go用户?我也希望你被证明是错的,当前的情况是非常不幸的。”马特·乔伊纳(Matt Joiner)但看起来Russ给出了相同的答案,当前运行时没有新线程。啊,我曾想过尝试使用C中的Go同步,但从来没有相反的方法。我看了一下,但一眼就看不出发生了什么。在looper示例或回调包中?两者都有。您能否提供一个示例c结构,在其上放置go回调,然后从c调用?@Matt:done,并更新答案。请让我知道你是如何处理这个例子的。这段代码的当前版本似乎根本没有使用rog的包。cgo本身是否发生了一些变化,从而允许这种情况,现在?@BadZen cgo很久以前就发生了一些变化。