1 回答
TA贡献1995条经验 获得超2个赞
害怕遇到这样一种情况:我调用了 C 例程,然后在 C 例程返回之后,但在我复制错误字符串之前,Go 调度程序决定将当前的 goroutine 换成另一个。...
这是一个合理的担忧吗?
是的。cgo“调用 C 代码”包装器在每次调用期间锁定一个 POSIX / OS 线程,但它们锁定的线程并非一直固定;实际上,只要您的 goroutine 正常运行,它确实会随着时间的推移跳转到多个不同的线程。(由于 Go 在当前实现中是协作调度的,在某些情况下,您可以小心不要做任何可能让您切换底层操作系统线程的事情,但这可能不是一个好计划。)
你可以在这里使用runtime.LockOSThread,但我认为最好的计划是:
我该如何解决?
在Go 恢复其正常的调度算法之前(即,在从 C/POSIX 线程解锁 goroutine 之前)获取错误。
cgo 以某种方式设法传播 errno 值...
它在从 POSIX 线程解锁 goroutine之前获取 errno 值。
我最初的计划是通过 cgo 调用 C,检查调用是否返回错误,如果是,则将错误字符串包装起来C.GoString,将其从原始字符指针转换为 Go 字符串。它看起来像C.GoString(C.get_error()).
如果有这样的变体获取错误号(而不是将其从 TLS 变量中取出),那么该计划应该仍然有效:只需确保您的 C 例程提供返回值和错误号即可。
如果没有,请按照您的建议编写自己的 C 包装器:
ftype wrapper_for_realfunc(char **errp, arg1type arg1, arg2type arg2) {
ftype ret = realfunc(arg1, arg2);
if IS_ERROR(ret) {
*errp = get_error();
} else {
*errp = NULL;
}
return ret;
}
现在你的 Go 包装器简单地调用包装器,它用一个额外的参数填充指向 C 内存的指针,*C.char如果没有错误,则将其设置为 nil,如果有错误,则将其设置为可以使用的东西C.GoString。
如果由于某种原因这不可行,请考虑使用runtime.LockOSThread及其对应的runtime.UnlockOSThread.
- 1 回答
- 0 关注
- 181 浏览
添加回答
举报
