Перенос строк ошибок из C ++ = & gt; C-упакованный API (многопоточный)

В настоящее время я обертываю существующую библиотеку C ++ для использования в Go. Чтобы сделать это, я должен обернуть его C-прокладкой, чтобы затем получить к нему доступ из Go. Хотя C ++ API вызывает исключения, и в настоящее время я сообщаю об ошибках, используя пользовательские значения в errnoЯ пытаюсь выяснить способ передачи строк ошибок из исключений.

Мои привязки берут выделенные указатели из API C ++ и упаковывают их непрозрачно => C => Go. Если бы я создал стороннюю библиотеку, я мог бы хранить последнюю ошибку прямо в классе, но мне нужно было бы связать ее где-то еще, очевидно.

Поскольку 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;

1

Решение

Вы можете реализовать свою оболочку для интерфейса C, который использует переменную контекста. Таким образом, вы даете контроль над проблемой потоков для вызывающей стороны.

Вот непроверенный пример:

wrapper.cpp

#include "wrapper.h"
struct context {
std::string last_error_message;
};

char const * ctx_get_last_error(context_handle ctx) {
if(ctx->last_error_message.empty()) return 0;
return ctx.last_error_message.c_str();
}

extern "C" context_handle create_context() {
return new context();
}

extern "C" void free_context(context_handle ctx) {
delete ctx;
}

extern "C" int my_lib_call(context_handle ctx, int some, char const * params) {
try {
lib_call(some, params);
}
catch(std::exception const & e) {
ctx->last_error_message = e.what();
return -1;
}
catch(...) {
ctx->last_error_message = "Unexpected error";
return -1;
}
return 0;
}

wrapper.h

#ifdef _cplusplus
extern "C" {
#endif
typedef struct context * context_handle;
context_handle create_context();
char const * ctx_get_last_error(context_handle ctx);
int my_lib_call(context_handle ctx, int some, char const * params);
#ifdef _cplusplus
}
#endif
1

Другие решения

Если ваши платформы все платформы POSIX, вы можете использовать pthread_[g|s]etspecific обрабатывать потоки конкретных данных. Страница открытой группы на pthread_key_create содержит пример того, как использовать эту функцию.

Вы можете создать небольшую библиотеку-оболочку, которая использует локальные переменные потока, если они доступны (_Thread_local является частью новых стандартов C и C ++, C11 и C ++ 11) и использует функции pthread в качестве запасного варианта, когда они недоступны.

AFAIR, Windows имеет аналогичные функции, но я не эксперт в этом.

1

Если вы действительно не хотите передавать дополнительный параметр, вам может понадобиться реализовать IPC (http://en.wikipedia.org/wiki/Inter-process_communication) система как очередь или именованный канал для передачи ваших данных.

0
По вопросам рекламы [email protected]