Столкнулся с библиотекой OTL, для которой в начале программы нужно сделать явную инициализацию посредством вызова otl_initialize, а затем -- otl_terminate:
int main() {
otl_connect::otl_initialize();
...
otl_connect::otl_terminate();
}
Мне интересно, насколько это распространенная практика для C/C++ библиотек. Буду признателен за перечисление известных вам библиотек, которым требуется явный init/deinit.
Спасибо.
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Здравствуйте, eao197, Вы писали:
E>Столкнулся с библиотекой OTL, для которой в начале программы нужно сделать явную инициализацию посредством вызова otl_initialize, а затем -- otl_terminate: E>
E>Мне интересно, насколько это распространенная практика для C/C++ библиотек. Буду признателен за перечисление известных вам библиотек, которым требуется явный init/deinit.
Здравствуйте, eao197, Вы писали:
E>Мне интересно, насколько это распространенная практика для C/C++ библиотек. Буду признателен за перечисление известных вам библиотек, которым требуется явный init/deinit.
По-моему это очень распространённая практика. Вот что дал беглый проход по библиотекам для работы с XML:
Более того, иногда требуется, что бы функция инициализации вызывалась глобально *и* для каждого потока в отдельности. Например: COMInitialize(). Я лично тоже так зачастую делаю.
Здравствуйте, eao197, Вы писали:
E>Мне интересно, насколько это распространенная практика для C/C++ библиотек. Буду признателен за перечисление известных вам библиотек, которым требуется явный init/deinit.
E>Мне интересно, насколько это распространенная практика для C/C++ библиотек. Буду признателен за перечисление известных вам библиотек, которым требуется явный init/deinit.
E>Спасибо.
Лично я считаю наличие таких функций моветоном.
Инициализация _библиотеки_ — крайне бессмысленное понятие и должно быть спрятано от пользователя этой библиотеки. Это наследие си (где полно глобальных функций).
Здравствуйте, eao197, Вы писали:
E>Мне интересно, насколько это распространенная практика для C/C++ библиотек. Буду признателен за перечисление известных вам библиотек, которым требуется явный init/deinit.
Да хотя бы WSAInitialize/WSACleanup из Winsock.
А вот <iostream> инициализирует свои объекты правильно.
uzhas пишет:
> Лично я считаю наличие таких функций моветоном. > Инициализация _библиотеки_ — крайне бессмысленное понятие и должно быть > спрятано от пользователя этой библиотеки.
Абсолютно не согласен. В С++ дофига проблем с инициализациий
статических глобальных данных (взять например проблему
потокобезопасной инициализации singleton-ов). А наличие такой функции
инициализации легко и просто разрешает проблему. И является
чуть ли не единственным способом сделать эту инициализацию вообще.
Здравствуйте, uzhas, Вы писали:
E>>Мне интересно, насколько это распространенная практика для C/C++ библиотек. Буду признателен за перечисление известных вам библиотек, которым требуется явный init/deinit.
E>>Спасибо.
U>Лично я считаю наличие таких функций моветоном. U>Инициализация _библиотеки_ — крайне бессмысленное понятие и должно быть спрятано от пользователя этой библиотеки. Это наследие си (где полно глобальных функций).
Ну хорошо, допустим функцию инициализации для процесса можно заменить ленивой инициализацией, заплатив дополнительной проверкой на основном пути. Допустим, функцию деинициализации для процесса можно вообще опустить, или зарегистрировать atexit(). Допустим инициализацию для потока можно тоже сделать ленивой. НО КАК БЫТЬ С ДЕИНИЦИАЛИЗАЦИЕЙ ДЛЯ ПОТОКА?
Как ты предлагаешь делать? Не освобождать ресурсы, связанные с потоком? А если приложение создаёт и рушит по 100 потоков в секунду?
Здравствуйте, eao197, Вы писали:
E>Мне интересно, насколько это распространенная практика для C/C++ библиотек. Буду признателен за перечисление известных вам библиотек, которым требуется явный init/deinit.
htmlayout static lib имеет Initialize/Finalize методы по двум соображениям:
1) не определен порядок статических конструкторов/деструкторов в lib, а надо.
2) тулзы проверющие расход памяти очень себя неадекватно ведут.
3) очень умный линковщик может выкинуть объекты инициализированные статически но которые нужны.
Например файл behavior_path.cpp
struct path: public behavior
{
// ctor
path(): behavior(HANDLE_DRAW, "path") {}
...
};
// instantiating and attaching it to the global list
path path_instance;
включенный в статическую библиотеку будет викинут линковщиком хотя инстанс:
path path_instance; // instantiating and attaching it to the global list
нужен в коде.
Re: Lib-ы которым нужен явный init/deinit
От:
Аноним
Дата:
26.03.08 13:45
Оценка:
Здравствуйте, eao197, Вы писали:
E>Столкнулся с библиотекой OTL, для которой в начале программы нужно сделать явную инициализацию посредством вызова otl_initialize, а затем -- otl_terminate: E>Мне интересно, насколько это распространенная практика для C/C++ библиотек. Буду признателен за перечисление известных вам библиотек, которым требуется явный init/deinit.
здесь упоминали про <iostream> (cout, cin..)
в главе 21(вроде. НО про потоки) у Страутсрупа (3изд) есть пара страниц на метод инициализации глобальных объектов
Здравствуйте, eao197, Вы писали:
E>Доброго дня!
E>Столкнулся с библиотекой OTL, для которой в начале программы нужно сделать явную инициализацию посредством вызова otl_initialize, а затем -- otl_terminate: E>
E>Мне интересно, насколько это распространенная практика для C/C++ библиотек. Буду признателен за перечисление известных вам библиотек, которым требуется явный init/deinit.
E>Спасибо.
Здравствуйте, remark, Вы писали:
R>Ну хорошо, допустим функцию инициализации для процесса можно заменить ленивой инициализацией, заплатив дополнительной проверкой на основном пути. Допустим, функцию деинициализации для процесса можно вообще опустить, или зарегистрировать atexit(). Допустим инициализацию для потока можно тоже сделать ленивой. НО КАК БЫТЬ С ДЕИНИЦИАЛИЗАЦИЕЙ ДЛЯ ПОТОКА? R>Как ты предлагаешь делать? Не освобождать ресурсы, связанные с потоком? А если приложение создаёт и рушит по 100 потоков в секунду?
В винде в статической библиотеке — повесьте отдельный поток, который следит за завершением тех потоков, о которых знает Ваша библиотека, и подчищает за ними.
В виндовой DLL функции DllMain сообщают о приходе/уходе потоков. Реально эти нотификации можно получить и в статической библиотеке, но я не очень знаю, как.
В юниксе можно создать TLS-объект с деструктором, его позовут при завершении потока.
Спасибо всем, кто привел свои примеры в данной теме. Стало понятно, что подобная инициализация широко используется и, как говорит c-smile, временами только она и работает надежно.
Мне эта информация нужна была для решения одной задачки: у меня есть программы, написанные с использованием плагинов. Т.е. существует некая стандартная реализация main(), в которой запускается плагинная система. Эта система затем грузит DLL-ки с плагинами и стартует сами плагины на основании информации из конфигурационных файлов. Одному из плагинов потребовалось использовать OTL и встал вопрос: как и когда вызывать otl_initialize/otl_terminate? Этот вопрос сложен еще и тем, что плагины загружаются и стартуют не на главной нити приложения, а на каких-то рабочих нитях.
В результате появилась следующая идея. Штатная реализация функции main получает вид:
int main( int argc, char ** argv ) {
try {
custom_app_init( argc, argv );
... остальные действия для системы плагинов ...
}
catch( const std::exception & x ) {
...
}
}
Где, по умолчанию, функция custom_app_init() пустая, не содержит никаких действий. Когда появляется необходимость инициализации 3rd party библиотек, программист пишет свою реализацию custom_app_init() вида:
Получится, что main вызовет custom_app_init, там будет создан экземпляр вспомогательного класса otl_starter_stopper_t, в конструкторе которого будет инициализированна OTL. При завершении приложения будет вызван деструктор этой статической переменной, в котором OTL будет деинициализированна.
Если приложению потребуется инициализация нескольких библиотек, то для каждой библиотеки в custom_app_init() должна быть своя статическая переменная:
С моей точки зрения, преимущества этого подхода в том, что если какая-то библиотека не проинициализировалась корректно, и было выброшено исключение, то деструкторы для всех предшествовавших ей объектов-инициализаторов все равно будут вызваны (т.е. произойдет корректная деинициализация уже инициализированных библиотек).
Смущает то, что не понятно, в какой именно момент будут вызываться деструкторы для подобных инициализаторов. И могут ли с этим быть связаны какие-то проблемы?
Может кто-нибудь подсказать, какие здесь есть подводные камни?
Более подробную информацию о том, зачем мне это понадобилось, можно найти здесь
SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Фактически так и сделано в Standard I/O library, только с подсчётом ссылок
27.4.2.1.6/1 The class Init describes an object whose construction ensures the construction of the eight objects
declared in <iostream> (27.3) that associate file stream buffers with the standard C streams provided for
by the functions declared in <cstdio> (27.8.2).
People who are more than casually interested in computers should have at least some idea of what the underlying hardware is like. Otherwise the programs they write will be pretty weird (c) D.Knuth
Здравствуйте, Pzz, Вы писали:
Pzz>Здравствуйте, remark, Вы писали:
R>>Ну хорошо, допустим функцию инициализации для процесса можно заменить ленивой инициализацией, заплатив дополнительной проверкой на основном пути. Допустим, функцию деинициализации для процесса можно вообще опустить, или зарегистрировать atexit(). Допустим инициализацию для потока можно тоже сделать ленивой. НО КАК БЫТЬ С ДЕИНИЦИАЛИЗАЦИЕЙ ДЛЯ ПОТОКА? R>>Как ты предлагаешь делать? Не освобождать ресурсы, связанные с потоком? А если приложение создаёт и рушит по 100 потоков в секунду?
Pzz>В винде в статической библиотеке — повесьте отдельный поток, который следит за завершением тех потоков, о которых знает Ваша библиотека, и подчищает за ними.
Pzz>В виндовой DLL функции DllMain сообщают о приходе/уходе потоков. Реально эти нотификации можно получить и в статической библиотеке, но я не очень знаю, как.
Pzz>В юниксе можно создать TLS-объект с деструктором, его позовут при завершении потока.
Pzz>Так что непреодолимых проблем нет
Согласен — с помошью отдельного потока можно более-менее решить.
Но останется та же засада, что и в WinSock (где работа с сетью вынесена в отдельный поток) — невозможно отлаживать в отладчике. Плюс — не понятно с какой частотой запускать процесс чистки. Синхронно при удалении потока нотифицировать не получится, а отложенно — непонятно сколько мусора накопится. Я, например, могу сделать ограничение для пользователя — что бы одновременно существовало не более N потоков работающих с библиотекой. С асинхронной сборкой это условие придётся переписать как — что бы одновременно существовало не более N потоков работающих с библиотекой + не создавайте потоки *слишком часто*, что такое *слишком часто* определяйте на практике методом тыка
Ну в общем не очень красиво получается.
С динамической библиотекой — с одной стороны лучше, но с другой свои проблемы. Заставять пользователя таскать за собой отдельную библиотеку...
Идеально было бы получать нотификации о создании/удалении потоков, но не с помощью отдельной динамической библиотеки. Но как это захачить под Win32, я не видел... Поищу в форуме Win32 — может кто знает...
> Идеально было бы получать нотификации о создании/удалении потоков, но не с > помощью отдельной динамической библиотеки. Но как это захачить под Win32, > я не видел... Поищу в форуме Win32 — может кто знает...
IMHO, в случае статической либы это можно захачить только если CRT тоже
прилинкована статически. Подробности можно посмотреть в boost::thread, в
реализации очистки tss. Смысл метода в том, что для очистки связаных с
потоком вещей сама CRT должна откуда-то получать нотификации. Ну она их и
получает, и при желании туда можно вклинится — там насколько помню есть
специальным образом названная PE-секция, и все что в ней лежит CRT считает
коллбэками на функции зачистки. То ли статья, то ли развернутый пост в
форуме про этот способ были на кодепроджекте. Другие способы широкой
общественности вроде как не известны. Я правда года два назад этим вопросом
интересовался, может чего и появилось с тех пор.
Posted via RSDN NNTP Server 2.1 beta
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Здравствуйте, remark, Вы писали:
R>Согласен — с помошью отдельного потока можно более-менее решить. R>Но останется та же засада, что и в WinSock (где работа с сетью вынесена в отдельный поток) — невозможно отлаживать в отладчике.
Что именно отлаживать? Поток, подчищающий за другими потоками?
R> Плюс — не понятно с какой частотой запускать процесс чистки. Синхронно при удалении потока нотифицировать не получится, а отложенно — непонятно сколько мусора накопится.
Завершение потока можно ждать с помощью WaitFor...(). Совершенно не обязательно устраивать поллинг.
R>С динамической библиотекой — с одной стороны лучше, но с другой свои проблемы. Заставять пользователя таскать за собой отдельную библиотеку...
R>Идеально было бы получать нотификации о создании/удалении потоков, но не с помощью отдельной динамической библиотеки. Но как это захачить под Win32, я не видел... Поищу в форуме Win32 — может кто знает...
Нотификации есть, но хорошо запрятаны. За 10 минут поиска по MSDN'у я не смог их найти
Здравствуйте, Pzz, Вы писали:
Pzz>Здравствуйте, remark, Вы писали:
R>>Согласен — с помошью отдельного потока можно более-менее решить. R>>Но останется та же засада, что и в WinSock (где работа с сетью вынесена в отдельный поток) — невозможно отлаживать в отладчике.
Pzz>Что именно отлаживать? Поток, подчищающий за другими потоками?
Да вообще всё.
Вот проходишь отладчиком по функции send(), а ничего на самом деле не отослалось. И когда отошлётся — не понятно.
R>> Плюс — не понятно с какой частотой запускать процесс чистки. Синхронно при удалении потока нотифицировать не получится, а отложенно — непонятно сколько мусора накопится.
Pzz>Завершение потока можно ждать с помощью WaitFor...(). Совершенно не обязательно устраивать поллинг.
Да, сам уже подумал, что если мы инициализировали поток, то получили его хендл. Теперь вспомогательный поток может ждать на этом хендле.
R>>С динамической библиотекой — с одной стороны лучше, но с другой свои проблемы. Заставять пользователя таскать за собой отдельную библиотеку...
R>>Идеально было бы получать нотификации о создании/удалении потоков, но не с помощью отдельной динамической библиотеки. Но как это захачить под Win32, я не видел... Поищу в форуме Win32 — может кто знает...
Pzz>Нотификации есть, но хорошо запрятаны. За 10 минут поиска по MSDN'у я не смог их найти
Да. Я тоже ничего не нахожу. Вообще глупо — понятно, что эта функциональность есть в Win, но почему она работает только для dll?! Почему нельзя сделать что-то типа RegisterThreadMonitor()? Или на худой конец — at_thread_exit(), что б можно было эмулировать объекты с деструкторами в TLS...
>> Идеально было бы получать нотификации о создании/удалении потоков, но не с >> помощью отдельной динамической библиотеки. Но как это захачить под Win32, >> я не видел... Поищу в форуме Win32 — может кто знает...
S>IMHO, в случае статической либы это можно захачить только если CRT тоже S>прилинкована статически. Подробности можно посмотреть в boost::thread, в S>реализации очистки tss. Смысл метода в том, что для очистки связаных с S>потоком вещей сама CRT должна откуда-то получать нотификации. Ну она их и S>получает, и при желании туда можно вклинится — там насколько помню есть S>специальным образом названная PE-секция, и все что в ней лежит CRT считает S>коллбэками на функции зачистки. То ли статья, то ли развернутый пост в S>форуме про этот способ были на кодепроджекте. Другие способы широкой S>общественности вроде как не известны. Я правда года два назад этим вопросом S>интересовался, может чего и появилось с тех пор.
То, что работает только со статическим ран-таймом я пока не нашёл. И это очень многообещающе.
Там только написано:
#if defined(BOOST_HAS_WINTHREADS) && defined(BOOST_THREAD_BUILD_LIB) && defined(_MSC_VER)
И в статье написано только:
Environment: Visual C++ 6 and above (may work on earlier versions too), for .exe's and DLL's running under Windows 95 and later, including console apps.