【发布时间】:2020-08-09 09:26:51
【问题描述】:
我正在用 cgo 包装一个 C 库,以供普通 Go 代码使用。
我的问题是我想将错误字符串传播到 Go API,但有问题的 C 库通过线程本地存储提供错误字符串;有一个全局的get_error() 调用,它返回一个指向线程本地字符数据的指针。
我最初的计划是通过 cgo 调用 C,检查调用是否返回错误,如果是,则使用 C.GoString 包装错误字符串,将其从原始字符指针转换为 Go 字符串。它看起来像C.GoString(C.get_error())。
我在这里预见到的问题是 C 中的 TLS 在本机操作系统线程级别上工作,但据我了解,调用 Go 代码将来自潜在的 N 个 goroutine 之一,这些 goroutine 在一定数量的底层本地多路复用Go 调度程序管理的线程池中的线程。
我害怕遇到这样一种情况:我调用了 C 例程,然后在 C 例程返回之后,但在我复制错误字符串之前,Go 调度程序决定将当前的 goroutine 换成另一个.当原始的 goroutine 被换回时,据我所知,它可能位于不同的本地线程上,但即使它被换回同一个线程,在此期间运行的任何 goroutine 都可能改变了状态的 TLS,导致我为不相关的调用加载错误字符串。
我的问题是:
- 这是一个合理的担忧吗?我是否误解了 go 调度程序或它与 cgo 交互的方式,这会导致这不是问题?
- 如果这是一个合理的问题,我该如何解决?
- cgo 以某种方式设法将 errno 值传播回调用 Go 代码,这些代码也存储在 TLS 中,这让我认为必须有一种安全的方法来执行此操作。
- 我想不出 C 代码本身可以被 go 调度程序抢占的方法,所以我应该引入一个包装 C 函数并让 IT 进行必要的调用,然后在返回备份之前有条件地复制错误字符串去戈兰?
我对任何允许我将错误字符串传播到 Go 其余部分的解决方案感兴趣,但我希望避免任何需要我围绕 TLS 序列化访问的解决方案,例如添加锁仅仅抓住一个错误字符串对我来说似乎非常不幸。
提前致谢!
【问题讨论】:
标签: c multithreading go cgo thread-local-storage