Обработчики файлов GoLang CGO

Я работаю с собственным бинарным файлом Linux C, который имеет довольно дорогой вызов инициализации, который я хотел бы выполнить один раз при запуске приложения. Этот вызов должен открыть кучу внутренних дескрипторов файлов для последующего использования. Когда я вызываю эту дорогостоящую C-функцию инициализации из Go, она успешно завершается и правильно открывает файлы, но эти дескрипторы открыты только на время вызова C-функции! Это означает, что когда я вызываю последовательные функции C для одной и той же библиотеки из Go, дескрипторы файлов больше не открываются, и вызовы завершаются ошибкой. Я проверил это с помощью команды lsof. Интересно, что когда вызов инициализации, а также вызовы последующего поведения объединяются в одну функцию C, которая затем вызывается из Go, файлы открываются и остаются открытыми, что позволяет успешно завершить все желаемые функции.

Есть ли какое-то недокументированное поведение cgo, которое «очищает», завершает работу или даже приводит к утечке файловых дескрипторов или других ресурсов с состоянием между несколькими вызовами функций C из Go? Если да, можно ли настроить это поведение? У нас нет доступа к исходному коду этой библиотеки.

Кроме того, я убедился, что это не связано с локальным хранилищем потока. Вызов 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).
}

person mdwhatcott    schedule 07.07.2014    source источник
comment
Можете ли вы предоставить работающий пример, который воспроизводит это поведение? Какую версию Go вы используете?   -  person nemo    schedule 07.07.2014
comment
Версии Go — 1.3 и 1.2. Я посмотрю, смогу ли я собрать пример, который показывает поведение...   -  person mdwhatcott    schedule 07.07.2014
comment
Я написал тривиальный пример, который, как я думал, будет воспроизводить поведение, но он работал, не демонстрируя плохого поведения. Я подозреваю, что в этой библиотеке C есть что-то странное. Точно сказать не могу...   -  person mdwhatcott    schedule 08.07.2014
comment
Хорошо, это немного смущает, но я понял это. Сразу после вызова initialize() я вызывал defer close(), но на самом деле это было defer fmt.Println(close()). Поскольку аргументы отложенных функций разрешаются немедленно (не откладываются), функция закрытия вызывалась до того, как мы могли вызвать какое-либо другое поведение. В блоге golang четко объясняется разрешение аргументов для отложенных вызовов функций: blog.golang.org/defer- паника и восстановление   -  person mdwhatcott    schedule 11.07.2014
comment
Ха-ха :) Рад, что вы его нашли. Вы можете ответить и принять свой собственный вопрос и пометить его как решенный таким образом.   -  person nemo    schedule 11.07.2014
comment
@mdwhatcott, я бы также сослался на соответствующий бит спецификации, поскольку он определяет поведение довольно строгое, просто язык немного суховат ;-)   -  person kostix    schedule 09.09.2014


Ответы (1)


Хорошо, это немного смущает, но я понял это. Сразу после вызова initialize() я вызывал defer close(), но на самом деле это было defer fmt.Println(close()). Поскольку аргументы отложенных функций разрешаются немедленно (не откладываются), функция закрытия вызывалась до того, как мы могли вызвать какое-либо другое поведение. В блоге golang четко объясняется разрешение аргументов для отложенных вызовов функций.

person mdwhatcott    schedule 13.07.2015