【发布时间】:2014-01-04 09:15:25
【问题描述】:
我目前正在包装一个现有的 C++ 库以在 Go 中使用。为此,我必须用 C 垫片包装它,然后从 Go 访问它。虽然 C++ API 引发异常,并且我目前正在使用 errno 中的自定义值来传达错误条件,但我正在尝试找出一种从异常中传达错误字符串的方法。
我的绑定从 C++ API 获取分配的指针,并将它们不透明地包装 => C => Go。如果我编写了第 3 方库,我本来可以将最后一个错误存储在类中,但显然我需要将它关联到其他地方。
因为 Go/cgo 是多线程的,所以我最初的想法是使用线程本地存储来存储错误字符串,并允许 Go 通过GetLastError() 函数抓取它。我发现的问题是在 OSX 上,没有线程本地存储(据我了解)。
免责声明:我的 C/C++ 技能是新手
如何从 C++ 端的异常中获取错误字符串,并以特定于线程的方式存储它以使其可用于我的 C 包装器(即可用于我的 Go 绑定),简而言之实际上在我的每一个可能出错的函数中都返回一个特殊的结构?还是我唯一的选择真的是让我的所有 C 函数都使用输出参数和特殊的错误结构返回类型?
编辑:(从上下文对象的建议中提出的想法)
如果我的 C++ -> C shim 像这样包装类:
// foo.h
#ifdef __cplusplus
extern "C" {
#endif
typedef void Thing;
const char* Thing_foo(Thing *ptr);
#ifdef __cplusplus
}
#endif
#endif
// foo.cpp
extern "C" {
const char* Thing_foo(Thing *ptr) {
return static_cast<CPP::Thing*>(ptr)->foo();
}
}
使用struct Thing同时携带指针和最后一个错误消息是否与上下文基本相同?
typedef struct Thing {
void *ptr;
char *last_err;
} Thing;
【问题讨论】:
-
如果这是您的问题,那么您应该考虑为您的库提供一个上下文对象,您可以在其中存储这样的数据。并且 Thread Local Storage 不会为您解决问题,即使它可以在 OSX 上运行。因为 Go 并不为每个 goroutine 使用一个线程。
-
@Vinzenz - 但是如何在没有线程本地存储的情况下管理线程特定的上下文?如果两个不同的线程访问对象并在不同的调用中生成单独的错误怎么办?或者更常见的......两个不同的调用通常会在不同的线程中产生错误,
-
你实现这个POSIX线程、pthread、平台的都是线程平台吗?
-
@jdi 使用上下文对象,您不需要线程本地存储。线程本地存储只不过是线程特定的全局变量。我不知道你的代码是什么样子的,但是为每个想要使用你的库的调用者创建一个上下文对象会有什么问题,你在内部存储诸如最后的错误消息等之类的东西。在你的 C API 中您总是将此上下文对象作为第一个参数传递。如果您从 Go 调用,您可以创建它并根据需要管理这些上下文对象,但恕我直言,这是最安全的方法。
-
@Vinzenz - 我想这比输出参数和自定义错误返回类型更容易切换。
标签: c++ c multithreading error-handling thread-local