4

我正在使用本机 linux C 二进制文件,它有一个相当昂贵的初始化调用,我想在应用程序启动时执行一次。这个调用应该在内部打开一堆文件句柄供以后使用。当我从 Go 调用这个昂贵的初始化 C 函数时,它成功完成并正确打开文件,但这些句柄仅在调用 C 函数期间打开!这意味着当我从 Go 中针对同一个库调用连续的 C 函数时,文件句柄不再打开并且调用失败。我已经使用 lsof 命令验证了这一点。有趣的是,当初始化调用以及对后续行为的调用被组合成一个 C 函数时,然后从 Go 调用该函数,文件将打开并保持打开状态,从而成功完成所有所需的功能。

是否存在某种未记录的 cgo 行为,即在从 Go 多次调用 C 函数之间“清理”、关闭甚至泄漏文件句柄或其他有状态资源?如果是这样,这种行为是否可配置?我们无权访问此库的源代码。

此外,我已经验证这与线程本地存储无关。调用runtime.LockOSThread()没有效果,我们已经验证了在控制权从 C 返回到调用 Go 代码后文件已关闭。

这是我想编写的 Go 代码示例:

// Go code:

func main() {
    C.Initialize()
    C.do_stuff() // internal state is already cleaned up! This call fails as a result. :(
}

这是一个同时调用初始化和行为的 C 函数示例。这个“包装”函数是从 Go 调用的:

// C code:

void DoEverything(void)
{
    Initialize();
    do_stuff(); // succeeds because all internal state is intact (not cleaned up).
}
4

1 回答 1

0

好吧,这有点尴尬,但我想通了。在调用 initialize() 之后,我正在调用 defer close(),但它实际上是 defer fmt.Println(close())。因为延迟函数的参数是立即解析的(不是延迟的),所以在我们调用任何其他行为之前调用了 close 函数。golang 博客清楚地解释了对延迟函数调用的参数解析

于 2015-07-13T15:49:41.947 回答