C 代码和 goroutine 调度

当我从 goroutine 调用 C 代码时,它是否会以任何方式影响其他 goroutine 的调度?我知道如果我在 Erlang 中调用 NIF,它会阻塞其他(Erlang)进程,直到函数返回。在 Golang 中是这样吗?C 代码会阻塞 goroutines 调度程序吗?


九州编程
浏览 310回答 2
2回答

呼如林

从 Go 代码调用 C 函数不会阻止其他 goroutine 运行。它确实对调度程序有影响。运行 C 函数的 goroutine 不一定要计入GOMAXPROCS限制。它将开始计算 GOMAXPROCS,但是如果 C 函数在 sysmon 后台 goroutine 运行时阻塞了超过 20us,那么如果有一个准备运行的 goroutine,调度程序将被允许启动另一个 goroutine。这些细节取决于特定的 Go 版本,可能会发生变化。

临摹微笑

这是一个非常好的问题,除了代码之外,我没有立即找到任何官方声明。我很高兴对官方文档有任何提示。答案是否定的, cgo 调用不会阻塞调度程序。对于以下内容,很高兴知道 Go 在内部使用G表示 goroutine,M表示机器(线程),P表示处理器。Goroutines 在机器上运行的处理器上运行。根据代码文档,从 G 调用 C 函数的工作方式如下:// To call into the C function f from Go, the cgo-generated code calls// runtime.cgocall(_cgo_Cfunc_f, frame), where _cgo_Cfunc_f is a// gcc-compiled function written by cgo.//// runtime.cgocall (below) locks g to m, calls entersyscall// so as not to block other goroutines or the garbage collector,// and then calls runtime.asmcgocall(_cgo_Cfunc_f, frame).//// runtime.asmcgocall (in asm_$GOARCH.s) switches to the m->g0 stack// (assumed to be an operating system-allocated stack, so safe to run// gcc-compiled code on) and calls _cgo_Cfunc_f(frame).//// _cgo_Cfunc_f invokes the actual C function f with arguments// taken from the frame structure, records the results in the frame,// and returns to runtime.asmcgocall.//// After it regains control, runtime.asmcgocall switches back to the// original g (m->curg)'s stack and returns to runtime.cgocall.//// After it regains control, runtime.cgocall calls exitsyscall, which blocks// until this m can run Go code without violating the $GOMAXPROCS limit,// and then unlocks g from m.entersyscall本质上是告诉运行时这个 goroutine 现在处于“外部”控制之下,就像我们对内核进行系统调用的情况一样。另一种可能是有用的一点是,锁定g到m(锁定CGO调用够程到操作系统的线程),运行时分配一个新的OS线程(理论上超过GOMAXPROCS)。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go