Re: Lib-ы которым нужен явный init/deinit
От: Mazay Россия  
Дата: 24.03.08 13:47
Оценка: 19 (1) +1 :)
Здравствуйте, eao197, Вы писали:

E>Мне интересно, насколько это распространенная практика для C/C++ библиотек. Буду признателен за перечисление известных вам библиотек, которым требуется явный init/deinit.


Дык хотя бы srand() для CRT'шного rand()

Или посерьёзнее: Библиотека от Агнера Фога
Главное гармония ...
Re: Lib-ы которым нужен явный init/deinit
От: c-smile Канада http://terrainformatica.com
Дата: 24.03.08 23:13
Оценка: 26 (2)
Здравствуйте, 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[2]: Lib-ы которым нужен явный init/deinit
От: MasterZiv СССР  
Дата: 24.03.08 20:44
Оценка: 1 (1) +1
uzhas пишет:

> Лично я считаю наличие таких функций моветоном.

> Инициализация _библиотеки_ — крайне бессмысленное понятие и должно быть
> спрятано от пользователя этой библиотеки.

Абсолютно не согласен. В С++ дофига проблем с инициализациий
статических глобальных данных (взять например проблему
потокобезопасной инициализации singleton-ов). А наличие такой функции
инициализации легко и просто разрешает проблему. И является
чуть ли не единственным способом сделать эту инициализацию вообще.
Posted via RSDN NNTP Server 2.1 beta
Re[5]: Lib-ы которым нужен явный init/deinit
От: Sergey Россия  
Дата: 27.03.08 11:22
Оценка: 30 (1)
> Идеально было бы получать нотификации о создании/удалении потоков, но не с
> помощью отдельной динамической библиотеки. Но как это захачить под Win32,
> я не видел... Поищу в форуме Win32 — может кто знает...

IMHO, в случае статической либы это можно захачить только если CRT тоже
прилинкована статически. Подробности можно посмотреть в boost::thread, в
реализации очистки tss. Смысл метода в том, что для очистки связаных с
потоком вещей сама CRT должна откуда-то получать нотификации. Ну она их и
получает, и при желании туда можно вклинится — там насколько помню есть
специальным образом названная PE-секция, и все что в ней лежит CRT считает
коллбэками на функции зачистки. То ли статья, то ли развернутый пост в
форуме про этот способ были на кодепроджекте. Другие способы широкой
общественности вроде как не известны. Я правда года два назад этим вопросом
интересовался, может чего и появилось с тех пор.
Posted via RSDN NNTP Server 2.1 beta
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[7]: Lib-ы которым нужен явный init/deinit
От: Sergey Россия  
Дата: 27.03.08 12:31
Оценка: 30 (1)
> Да. Действительно. Я ведь там смотрел. Но куда-то не туда посмотрел, и
> решил, что они всё ещё требуют чтобы thread был как dll под win32.
> Вот статья:
> http://www.codeguru.com/Cpp/misc/misc/threadsprocesses/article.php/c6945__2/
>
> Реализация в libs\thread\src\tss_pe.cpp
>
> То, что работает только со статическим ран-таймом я пока не нашёл.

Это мои личные наблюдения. Авторы библиотеки об этой проблеме видимо не в
курсе. Я не помню, писал я про такую багу в бустогруппы или не писал. Если
не лень — убедитесь, что оно не работает и напишите в comp.lib.boost.devel.

> И это очень многообещающе.


Нифига. Оно реально не работает. CRT ищет эту секцию у себя, а не во всех
принадлежащих процессу модулях. Соответственно, в случае статической
линковки все замечательно, в случае динамической — не работает.

> Там только написано:

> #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.
>
>

Таки смотреть надо в код CRT, мало ли кто чего на кодепроджекте напишет.
Posted via RSDN NNTP Server 2.1 beta
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
Re[3]: Lib-ы которым нужен явный init/deinit
От: Pzz Россия https://github.com/alexpevzner
Дата: 27.03.08 01:14
Оценка: 20 (1)
Здравствуйте, remark, Вы писали:

R>Ну хорошо, допустим функцию инициализации для процесса можно заменить ленивой инициализацией, заплатив дополнительной проверкой на основном пути. Допустим, функцию деинициализации для процесса можно вообще опустить, или зарегистрировать atexit(). Допустим инициализацию для потока можно тоже сделать ленивой. НО КАК БЫТЬ С ДЕИНИЦИАЛИЗАЦИЕЙ ДЛЯ ПОТОКА?

R>Как ты предлагаешь делать? Не освобождать ресурсы, связанные с потоком? А если приложение создаёт и рушит по 100 потоков в секунду?

В винде в статической библиотеке — повесьте отдельный поток, который следит за завершением тех потоков, о которых знает Ваша библиотека, и подчищает за ними.

В виндовой DLL функции DllMain сообщают о приходе/уходе потоков. Реально эти нотификации можно получить и в статической библиотеке, но я не очень знаю, как.

В юниксе можно создать TLS-объект с деструктором, его позовут при завершении потока.

Так что непреодолимых проблем нет
Re: Lib-ы которым нужен явный init/deinit
От: Conr Россия  
Дата: 24.03.08 12:34
Оценка: 19 (1)
Здравствуйте, eao197, Вы писали:

E>Столкнулся с библиотекой OTL, для которой в начале программы нужно сделать явную инициализацию посредством вызова otl_initialize, а затем -- otl_terminate:

E>
E>int main() {
E>  otl_connect::otl_initialize();
E>  ...
E>  otl_connect::otl_terminate();
E>}
E>


E>Мне интересно, насколько это распространенная практика для C/C++ библиотек. Буду признателен за перечисление известных вам библиотек, которым требуется явный init/deinit.


Сходу только Botan и libcurl вспоминаются.
Re: Lib-ы которым нужен явный init/deinit
От: remark Россия http://www.1024cores.net/
Дата: 24.03.08 12:35
Оценка: 19 (1)
Здравствуйте, eao197, Вы писали:

E>Мне интересно, насколько это распространенная практика для C/C++ библиотек. Буду признателен за перечисление известных вам библиотек, которым требуется явный init/deinit.



По-моему это очень распространённая практика. Вот что дал беглый проход по библиотекам для работы с XML:

Apache Portable Runtime (http://apr.apache.org/docs/apr/0.9/group__apr__library.html):
apr_initialize()/apr_terminate()

Xerces-C++ (http://xerces.apache.org/xerces-c/apiDocs/classXMLPlatformUtils.html#378a0935e1d80c64b7a53dc35baad8f6):
XMLPlatformUtils::Initialize()/XMLPlatformUtils::Terminate()

libxml2 (http://xmlsoft.org/html/libxml-globals.html#xmlInitGlobals):
xmlInitializeGlobalState()

libcurl (http://curl.haxx.se/libcurl/c/libcurl-tutorial.html):
curl_global_init()


Более того, иногда требуется, что бы функция инициализации вызывалась глобально *и* для каждого потока в отдельности. Например: COMInitialize(). Я лично тоже так зачастую делаю.



1024cores — all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re: Lib-ы которым нужен явный init/deinit
От: zaufi Земля  
Дата: 24.03.08 13:37
Оценка: 19 (1)
ну и в догонку libltdl (портабельная работа с динамиескими библами. часть libtool'a) требует lt_dlinit/lt_dlexit
Re: Lib-ы которым нужен явный init/deinit
От: iyura  
Дата: 26.03.08 15:39
Оценка: 19 (1)
Здравствуйте, eao197, Вы писали:

E>Доброго дня!


E>Столкнулся с библиотекой OTL, для которой в начале программы нужно сделать явную инициализацию посредством вызова otl_initialize, а затем -- otl_terminate:

E>
E>int main() {
E>  otl_connect::otl_initialize();
E>  ...
E>  otl_connect::otl_terminate();
E>}
E>


E>Мне интересно, насколько это распространенная практика для C/C++ библиотек. Буду признателен за перечисление известных вам библиотек, которым требуется явный init/deinit.


E>Спасибо.


Stingray... например Objective Grid
Re[2]: 27.4.2.1.6
От: gear nuke  
Дата: 27.03.08 09:02
Оценка: 19 (1)
Здравствуйте, eao197,

Фактически так и сделано в 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
Lib-ы которым нужен явный init/deinit
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 24.03.08 11:56
Оценка:
Доброго дня!

Столкнулся с библиотекой OTL, для которой в начале программы нужно сделать явную инициализацию посредством вызова otl_initialize, а затем -- otl_terminate:
int main() {
  otl_connect::otl_initialize();
  ...
  otl_connect::otl_terminate();
}


Мне интересно, насколько это распространенная практика для C/C++ библиотек. Буду признателен за перечисление известных вам библиотек, которым требуется явный init/deinit.

Спасибо.


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re: Lib-ы которым нужен явный init/deinit
От: uzhas Ниоткуда  
Дата: 24.03.08 19:52
Оценка:
E>Мне интересно, насколько это распространенная практика для C/C++ библиотек. Буду признателен за перечисление известных вам библиотек, которым требуется явный init/deinit.

E>Спасибо.


Лично я считаю наличие таких функций моветоном.
Инициализация _библиотеки_ — крайне бессмысленное понятие и должно быть спрятано от пользователя этой библиотеки. Это наследие си (где полно глобальных функций).
Re: Lib-ы которым нужен явный init/deinit
От: Roman Odaisky Украина  
Дата: 24.03.08 20:11
Оценка:
Здравствуйте, eao197, Вы писали:

E>Мне интересно, насколько это распространенная практика для C/C++ библиотек. Буду признателен за перечисление известных вам библиотек, которым требуется явный init/deinit.


Да хотя бы WSAInitialize/WSACleanup из Winsock.

А вот <iostream> инициализирует свои объекты правильно.
До последнего не верил в пирамиду Лебедева.
Re[2]: Lib-ы которым нужен явный init/deinit
От: remark Россия http://www.1024cores.net/
Дата: 24.03.08 22:01
Оценка:
Здравствуйте, uzhas, Вы писали:

E>>Мне интересно, насколько это распространенная практика для C/C++ библиотек. Буду признателен за перечисление известных вам библиотек, которым требуется явный init/deinit.


E>>Спасибо.


U>Лично я считаю наличие таких функций моветоном.

U>Инициализация _библиотеки_ — крайне бессмысленное понятие и должно быть спрятано от пользователя этой библиотеки. Это наследие си (где полно глобальных функций).


Ну хорошо, допустим функцию инициализации для процесса можно заменить ленивой инициализацией, заплатив дополнительной проверкой на основном пути. Допустим, функцию деинициализации для процесса можно вообще опустить, или зарегистрировать atexit(). Допустим инициализацию для потока можно тоже сделать ленивой. НО КАК БЫТЬ С ДЕИНИЦИАЛИЗАЦИЕЙ ДЛЯ ПОТОКА?
Как ты предлагаешь делать? Не освобождать ресурсы, связанные с потоком? А если приложение создаёт и рушит по 100 потоков в секунду?



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
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изд) есть пара страниц на метод инициализации глобальных объектов
Re: Оцените решение
От: eao197 Беларусь http://eao197.blogspot.com
Дата: 27.03.08 07:09
Оценка:
Спасибо всем, кто привел свои примеры в данной теме. Стало понятно, что подобная инициализация широко используется и, как говорит 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() вида:
class otl_starter_stopper_t {
  public :
    otl_starter_stopper_t() { otl_connect::otl_initialize(); }
    ~otl_starter_stopper_t() { otl_connect::otl_terminate(); }
};

void
custom_app_init() {
  static otl_starter_stopper_t otl_starter;
}


Получится, что main вызовет custom_app_init, там будет создан экземпляр вспомогательного класса otl_starter_stopper_t, в конструкторе которого будет инициализированна OTL. При завершении приложения будет вызван деструктор этой статической переменной, в котором OTL будет деинициализированна.

Если приложению потребуется инициализация нескольких библиотек, то для каждой библиотеки в custom_app_init() должна быть своя статическая переменная:
void
custom_app_init() {
  static otl_starter_stopper_t otl_starter;
  static libxms2_initializer_t xml2_initializer;
  static libcurl_initializer_t libcurl_initializer;
}


С моей точки зрения, преимущества этого подхода в том, что если какая-то библиотека не проинициализировалась корректно, и было выброшено исключение, то деструкторы для всех предшествовавших ей объектов-инициализаторов все равно будут вызваны (т.е. произойдет корректная деинициализация уже инициализированных библиотек).

Смущает то, что не понятно, в какой именно момент будут вызываться деструкторы для подобных инициализаторов. И могут ли с этим быть связаны какие-то проблемы?

Может кто-нибудь подсказать, какие здесь есть подводные камни?

Более подробную информацию о том, зачем мне это понадобилось, можно найти здесь


SObjectizer: <микро>Агентно-ориентированное программирование на C++.
Re[4]: Lib-ы которым нужен явный init/deinit
От: remark Россия http://www.1024cores.net/
Дата: 27.03.08 10:44
Оценка:
Здравствуйте, Pzz, Вы писали:

Pzz>Здравствуйте, remark, Вы писали:


R>>Ну хорошо, допустим функцию инициализации для процесса можно заменить ленивой инициализацией, заплатив дополнительной проверкой на основном пути. Допустим, функцию деинициализации для процесса можно вообще опустить, или зарегистрировать atexit(). Допустим инициализацию для потока можно тоже сделать ленивой. НО КАК БЫТЬ С ДЕИНИЦИАЛИЗАЦИЕЙ ДЛЯ ПОТОКА?

R>>Как ты предлагаешь делать? Не освобождать ресурсы, связанные с потоком? А если приложение создаёт и рушит по 100 потоков в секунду?

Pzz>В винде в статической библиотеке — повесьте отдельный поток, который следит за завершением тех потоков, о которых знает Ваша библиотека, и подчищает за ними.


Pzz>В виндовой DLL функции DllMain сообщают о приходе/уходе потоков. Реально эти нотификации можно получить и в статической библиотеке, но я не очень знаю, как.


Pzz>В юниксе можно создать TLS-объект с деструктором, его позовут при завершении потока.


Pzz>Так что непреодолимых проблем нет


Согласен — с помошью отдельного потока можно более-менее решить.
Но останется та же засада, что и в WinSock (где работа с сетью вынесена в отдельный поток) — невозможно отлаживать в отладчике. Плюс — не понятно с какой частотой запускать процесс чистки. Синхронно при удалении потока нотифицировать не получится, а отложенно — непонятно сколько мусора накопится. Я, например, могу сделать ограничение для пользователя — что бы одновременно существовало не более N потоков работающих с библиотекой. С асинхронной сборкой это условие придётся переписать как — что бы одновременно существовало не более N потоков работающих с библиотекой + не создавайте потоки *слишком часто*, что такое *слишком часто* определяйте на практике методом тыка
Ну в общем не очень красиво получается.

С динамической библиотекой — с одной стороны лучше, но с другой свои проблемы. Заставять пользователя таскать за собой отдельную библиотеку...

Идеально было бы получать нотификации о создании/удалении потоков, но не с помощью отдельной динамической библиотеки. Но как это захачить под Win32, я не видел... Поищу в форуме Win32 — может кто знает...



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[5]: Lib-ы которым нужен явный init/deinit
От: Pzz Россия https://github.com/alexpevzner
Дата: 27.03.08 11:33
Оценка:
Здравствуйте, remark, Вы писали:

R>Согласен — с помошью отдельного потока можно более-менее решить.

R>Но останется та же засада, что и в WinSock (где работа с сетью вынесена в отдельный поток) — невозможно отлаживать в отладчике.

Что именно отлаживать? Поток, подчищающий за другими потоками?

R> Плюс — не понятно с какой частотой запускать процесс чистки. Синхронно при удалении потока нотифицировать не получится, а отложенно — непонятно сколько мусора накопится.


Завершение потока можно ждать с помощью WaitFor...(). Совершенно не обязательно устраивать поллинг.

R>С динамической библиотекой — с одной стороны лучше, но с другой свои проблемы. Заставять пользователя таскать за собой отдельную библиотеку...


R>Идеально было бы получать нотификации о создании/удалении потоков, но не с помощью отдельной динамической библиотеки. Но как это захачить под Win32, я не видел... Поищу в форуме Win32 — может кто знает...


Нотификации есть, но хорошо запрятаны. За 10 минут поиска по MSDN'у я не смог их найти
Re[6]: Lib-ы которым нужен явный init/deinit
От: remark Россия http://www.1024cores.net/
Дата: 27.03.08 12:02
Оценка:
Здравствуйте, 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...


1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[6]: Lib-ы которым нужен явный init/deinit
От: remark Россия http://www.1024cores.net/
Дата: 27.03.08 12:15
Оценка:
Здравствуйте, Sergey, Вы писали:


>> Идеально было бы получать нотификации о создании/удалении потоков, но не с

>> помощью отдельной динамической библиотеки. Но как это захачить под Win32,
>> я не видел... Поищу в форуме Win32 — может кто знает...

S>IMHO, в случае статической либы это можно захачить только если CRT тоже

S>прилинкована статически. Подробности можно посмотреть в boost::thread, в
S>реализации очистки tss. Смысл метода в том, что для очистки связаных с
S>потоком вещей сама CRT должна откуда-то получать нотификации. Ну она их и
S>получает, и при желании туда можно вклинится — там насколько помню есть
S>специальным образом названная PE-секция, и все что в ней лежит CRT считает
S>коллбэками на функции зачистки. То ли статья, то ли развернутый пост в
S>форуме про этот способ были на кодепроджекте. Другие способы широкой
S>общественности вроде как не известны. Я правда года два назад этим вопросом
S>интересовался, может чего и появилось с тех пор.


Да. Действительно. Я ведь там смотрел. Но куда-то не туда посмотрел, и решил, что они всё ещё требуют чтобы thread был как dll под win32.
Вот статья:
http://www.codeguru.com/Cpp/misc/misc/threadsprocesses/article.php/c6945__2/

Реализация в libs\thread\src\tss_pe.cpp

То, что работает только со статическим ран-таймом я пока не нашёл. И это очень многообещающе.
Там только написано:
#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.




1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[7]: Lib-ы которым нужен явный init/deinit
От: Pzz Россия https://github.com/alexpevzner
Дата: 27.03.08 12:15
Оценка:
Здравствуйте, remark, Вы писали:

Pzz>>Что именно отлаживать? Поток, подчищающий за другими потоками?


R>Да вообще всё.

R>Вот проходишь отладчиком по функции send(), а ничего на самом деле не отослалось. И когда отошлётся — не понятно.

Ну это относится к многопоточности вообще, а не только к рассматриваемому нами случаю.

Pzz>>Завершение потока можно ждать с помощью WaitFor...(). Совершенно не обязательно устраивать поллинг.


R>Да, сам уже подумал, что если мы инициализировали поток, то получили его хендл. Теперь вспомогательный поток может ждать на этом хендле.


Если мы говорим о библиотеке, то собственно создание пользовательских потоков мы не контроллируем. Но хендл текущего потока всегда можно получить, вот таким примерно образом:

    HANDLE thread_handle;

    DuplicateHandle(
        GetCurrentProcess(),
        GetCurrentThread(),
        GetCurrentProcess(),
        &thread_handle,
        0,
        FALSE,
        DUPLICATE_SAME_ACCESS
    );


Pzz>>Нотификации есть, но хорошо запрятаны. За 10 минут поиска по MSDN'у я не смог их найти


R>Да. Я тоже ничего не нахожу. Вообще глупо — понятно, что эта функциональность есть в Win, но почему она работает только для dll?! Почему нельзя сделать что-то типа RegisterThreadMonitor()? Или на худой конец — at_thread_exit(), что б можно было эмулировать объекты с деструкторами в TLS...


Чтобы жизнь мёдом не казалась

В Висте наконец добавили FlsAlloc(), который аллоцирует fiber local storage с деструктором. Вроде обещают звать эту функцию при завершении как фибера, так и потока.
Re: Lib-ы которым нужен явный init/deinit
От: Alex Alexandrov США  
Дата: 27.03.08 21:39
Оценка:
Здравствуйте, eao197, Вы писали:

E>Мне интересно, насколько это распространенная практика для C/C++ библиотек. Буду признателен за перечисление известных вам библиотек, которым требуется явный init/deinit.


У libxml, насколько я помню, тоже такие функции есть. Но она сишная.

Вообще, такие функции в кроссплатформенных библиотеках вещь неплохая. Чтобы была возможность все под контролем держать. Инициализация/деинициализация в конструкторах/деструкторах глобальных переменных — вещь опасная иногда.
It's kind of fun to do the impossible (Walt Disney)
Re[8]: Lib-ы которым нужен явный init/deinit
От: Alex Alexandrov США  
Дата: 28.03.08 19:19
Оценка:
Здравствуйте, Sergey, Вы писали:


>> И это очень многообещающе.


S>Нифига. Оно реально не работает. CRT ищет эту секцию у себя, а не во всех

S>принадлежащих процессу модулях. Соответственно, в случае статической
S>линковки все замечательно, в случае динамической — не работает.

Непонятно. Что значит, "CRT ищет эту секцию у себя"? Ведь тот же механизм используется для вызова конструкторов/деструкторов глобальных объектов? Как же там все это находится?

Кроме того, для того, чтобы нас уведомлять о создании/смерти потока, CRT сама должна получить эти нотификации откуда-то? Т.е. у нее должен быть свой DllMain? Или уведомления придут только в случае другие потоки создаются через _beginthread/_beginthreadex?
It's kind of fun to do the impossible (Walt Disney)
Re[7]: Lib-ы которым нужен явный init/deinit
От: gear nuke  
Дата: 29.03.08 07:17
Оценка:
Здравствуйте, remark, Вы писали:

R>http://www.codeguru.com/Cpp/misc/misc/threadsprocesses/article.php/c6945__2/


По-моему, это не то. Вообще, использование atexit для вызовов дестракторов вроде бы и в MSDN где-то документировано было, и другие примеры встречаются. Но вызывается это при завершении первичного треда, да и то, если оно не аварийное.

Нотификаторы на создание\уничтожение треда (согдасно MSDN) есть только в ядре. Однако, есть и "полудокументированный" механизм — см. DLL_THREAD_DETACH в DllMain. Загрузчик создаёт список загруженных модулей, где хранятся и их точки входа. Здесь можно подумать о разных вариантах: от ручного добавления ldr_data_table_entry, до вполне легального — создания и загрузки прокси-dll.
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
Re[8]: Lib-ы которым нужен явный init/deinit
От: remark Россия http://www.1024cores.net/
Дата: 29.03.08 10:35
Оценка:
Здравствуйте, Sergey, Вы писали:

>> Да. Действительно. Я ведь там смотрел. Но куда-то не туда посмотрел, и

>> решил, что они всё ещё требуют чтобы thread был как dll под win32.
>> Вот статья:
>> http://www.codeguru.com/Cpp/misc/misc/threadsprocesses/article.php/c6945__2/
>>
>> Реализация в libs\thread\src\tss_pe.cpp
>>
>> То, что работает только со статическим ран-таймом я пока не нашёл.

S>Это мои личные наблюдения. Авторы библиотеки об этой проблеме видимо не в

S>курсе. Я не помню, писал я про такую багу в бустогруппы или не писал. Если
S>не лень — убедитесь, что оно не работает и напишите в comp.lib.boost.devel.

>> И это очень многообещающе.


S>Нифига. Оно реально не работает. CRT ищет эту секцию у себя, а не во всех

S>принадлежащих процессу модулях. Соответственно, в случае статической
S>линковки все замечательно, в случае динамической — не работает.

Проверил. Их версия у меня не работает только под release, т.к. линкер выкидывает некоторые переменные. А статический или динамический ран-тайм не влияет.

Пофиксил это. Выложил рабочую версию:
http://www.rsdn.ru/forum/message/2895408.1.aspx
Автор: remark
Дата: 29.03.08




1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[9]: Lib-ы которым нужен явный init/deinit
От: remark Россия http://www.1024cores.net/
Дата: 29.03.08 10:37
Оценка:
Здравствуйте, Alex Alexandrov, Вы писали:

AA>Здравствуйте, Sergey, Вы писали:



>>> И это очень многообещающе.


S>>Нифига. Оно реально не работает. CRT ищет эту секцию у себя, а не во всех

S>>принадлежащих процессу модулях. Соответственно, в случае статической
S>>линковки все замечательно, в случае динамической — не работает.

AA>Непонятно. Что значит, "CRT ищет эту секцию у себя"? Ведь тот же механизм используется для вызова конструкторов/деструкторов глобальных объектов? Как же там все это находится?


AA>Кроме того, для того, чтобы нас уведомлять о создании/смерти потока, CRT сама должна получить эти нотификации откуда-то? Т.е. у нее должен быть свой DllMain? Или уведомления придут только в случае другие потоки создаются через _beginthread/_beginthreadex?


Да, статический или динамический рантайм действительно не влияет.
Выложил рабочую версию:
http://www.rsdn.ru/forum/message/2895408.1.aspx
Автор: remark
Дата: 29.03.08




1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[8]: Lib-ы которым нужен явный init/deinit
От: remark Россия http://www.1024cores.net/
Дата: 29.03.08 10:38
Оценка:
Здравствуйте, gear nuke, Вы писали:

GN>Здравствуйте, remark, Вы писали:


R>>http://www.codeguru.com/Cpp/misc/misc/threadsprocesses/article.php/c6945__2/


GN>По-моему, это не то. Вообще, использование atexit для вызовов дестракторов вроде бы и в MSDN где-то документировано было, и другие примеры встречаются. Но вызывается это при завершении первичного треда, да и то, если оно не аварийное.


GN>Нотификаторы на создание\уничтожение треда (согдасно MSDN) есть только в ядре. Однако, есть и "полудокументированный" механизм — см. DLL_THREAD_DETACH в DllMain. Загрузчик создаёт список загруженных модулей, где хранятся и их точки входа. Здесь можно подумать о разных вариантах: от ручного добавления ldr_data_table_entry, до вполне легального — создания и загрузки прокси-dll.


http://www.rsdn.ru/forum/message/2895408.1.aspx
Автор: remark
Дата: 29.03.08



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[3]: Lib-ы которым нужен явный init/deinit
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 29.03.08 19:28
Оценка:
Здравствуйте, remark, Вы писали:

R>Ну хорошо, допустим функцию инициализации для процесса можно заменить ленивой инициализацией, заплатив дополнительной проверкой на основном пути. Допустим, функцию деинициализации для процесса можно вообще опустить, или зарегистрировать atexit(). Допустим инициализацию для потока можно тоже сделать ленивой. НО КАК БЫТЬ С ДЕИНИЦИАЛИЗАЦИЕЙ ДЛЯ ПОТОКА?


Деинициализировать при выходе, почему бы нет?;)) Сделать булевский флаг...
Ну или разрешить многократную инициализацию и деинициализацию.

R>Как ты предлагаешь делать? Не освобождать ресурсы, связанные с потоком? А если приложение создаёт и рушит по 100 потоков в секунду?


А это вообще диверсия (если речь не идёт про явно специализированные случаи типа эрланга). Используйте пулы тредов.;)
The God is real, unless declared integer.
Re[9]: Lib-ы которым нужен явный init/deinit
От: gear nuke  
Дата: 29.03.08 21:05
Оценка:
Здравствуйте, remark, Вы писали:

R>http://www.rsdn.ru/forum/message/2895408.1.aspx
Автор: remark
Дата: 29.03.08


Ага, не дочитал Хорошее решение, особенно в плане того, что способ как бы для этого и присутствует в ОС. Только вот лучше ли оно документировано... Традиционно TLS используют в протекторах, что бы проверить, не прицеплен ли отладчик...
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
Re[4]: Lib-ы которым нужен явный init/deinit
От: remark Россия http://www.1024cores.net/
Дата: 30.03.08 21:09
Оценка:
Здравствуйте, netch80, Вы писали:

N>Здравствуйте, remark, Вы писали:


R>>Ну хорошо, допустим функцию инициализации для процесса можно заменить ленивой инициализацией, заплатив дополнительной проверкой на основном пути. Допустим, функцию деинициализации для процесса можно вообще опустить, или зарегистрировать atexit(). Допустим инициализацию для потока можно тоже сделать ленивой. НО КАК БЫТЬ С ДЕИНИЦИАЛИЗАЦИЕЙ ДЛЯ ПОТОКА?


N>Деинициализировать при выходе, почему бы нет?) Сделать булевский флаг...



Как отловить момент завершения потока?

Ну хотя сейчас я уже знаю:
http://www.rsdn.ru/forum/message/2895408.1.aspx
Автор: remark
Дата: 29.03.08



N>Ну или разрешить многократную инициализацию и деинициализацию.



Если я правильно понял, то речь не об этом. Речь о том, как инициализировать/деинициализировать ресурсы, выделенные для конкретного потока, а не глобальные.


R>>Как ты предлагаешь делать? Не освобождать ресурсы, связанные с потоком? А если приложение создаёт и рушит по 100 потоков в секунду?


N>А это вообще диверсия (если речь не идёт про явно специализированные случаи типа эрланга). Используйте пулы тредов.



Т.е. предлагаешь не инженерное решение, а организационное — автор библиотеки должен постоянно обходить всех клиентов и говорить "Используйте пулы тредов. Пожалуйста."



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[5]: Lib-ы которым нужен явный init/deinit
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 31.03.08 06:38
Оценка:
Здравствуйте, remark, Вы писали:

R>>>Ну хорошо, допустим функцию инициализации для процесса можно заменить ленивой инициализацией, заплатив дополнительной проверкой на основном пути. Допустим, функцию деинициализации для процесса можно вообще опустить, или зарегистрировать atexit(). Допустим инициализацию для потока можно тоже сделать ленивой. НО КАК БЫТЬ С ДЕИНИЦИАЛИЗАЦИЕЙ ДЛЯ ПОТОКА?

N>>Деинициализировать при выходе, почему бы нет?;)) Сделать булевский флаг...
R>Как отловить момент завершения потока?

R>Ну хотя сейчас я уже знаю:

R>http://www.rsdn.ru/forum/message/2895408.1.aspx
Автор: remark
Дата: 29.03.08


Как завершается тред? Если форсированным убийством без права пискнуть, то всё плохо по-любому. Если обычным путём, управляемым средой языка (return или исключение), то достаточно объекта со счётчиком и логикой "init/deinit только на переходах счётчика между 0 и 1", устанавливаемого в тред в стиле RAII.

N>>Ну или разрешить многократную инициализацию и деинициализацию.


R>Если я правильно понял, то речь не об этом. Речь о том, как инициализировать/деинициализировать ресурсы, выделенные для конкретного потока, а не глобальные.


О выполнении init/deinit в контексте именно данного треда, насколько я понимаю, заботится библиотека.

R>>>Как ты предлагаешь делать? Не освобождать ресурсы, связанные с потоком? А если приложение создаёт и рушит по 100 потоков в секунду?

N>>А это вообще диверсия (если речь не идёт про явно специализированные случаи типа эрланга). Используйте пулы тредов.;)
R>Т.е. предлагаешь не инженерное решение, а организационное — автор библиотеки должен постоянно обходить всех клиентов и говорить "Используйте пулы тредов. Пожалуйста." :)))

Ему как раз пофиг. Не пофиг — автору конечной программы.
The God is real, unless declared integer.
Re[6]: Lib-ы которым нужен явный init/deinit
От: remark Россия http://www.1024cores.net/
Дата: 31.03.08 09:57
Оценка:
Здравствуйте, netch80, Вы писали:

N>Здравствуйте, remark, Вы писали:


R>>>>Ну хорошо, допустим функцию инициализации для процесса можно заменить ленивой инициализацией, заплатив дополнительной проверкой на основном пути. Допустим, функцию деинициализации для процесса можно вообще опустить, или зарегистрировать atexit(). Допустим инициализацию для потока можно тоже сделать ленивой. НО КАК БЫТЬ С ДЕИНИЦИАЛИЗАЦИЕЙ ДЛЯ ПОТОКА?

N>>>Деинициализировать при выходе, почему бы нет?) Сделать булевский флаг...
R>>Как отловить момент завершения потока?

R>>Ну хотя сейчас я уже знаю:

R>>http://www.rsdn.ru/forum/message/2895408.1.aspx
Автор: remark
Дата: 29.03.08


N>Как завершается тред? Если форсированным убийством без права пискнуть, то всё плохо по-любому. Если обычным путём, управляемым средой языка (return или исключение), то достаточно объекта со счётчиком и логикой "init/deinit только на переходах счётчика между 0 и 1", устанавливаемого в тред в стиле RAII.



Тогда я не понял твоего тезиса... Ты с чем-то несогласен? Или что-то предлагаешь?
Можешь пояснить?


N>>>Ну или разрешить многократную инициализацию и деинициализацию.


R>>Если я правильно понял, то речь не об этом. Речь о том, как инициализировать/деинициализировать ресурсы, выделенные для конкретного потока, а не глобальные.


N>О выполнении init/deinit в контексте именно данного треда, насколько я понимаю, заботится библиотека.



О библиотеке как раз и идёт речь. Т.е. ответы типа "а библиотека как-то там это сама сделает" не катят


R>>>>Как ты предлагаешь делать? Не освобождать ресурсы, связанные с потоком? А если приложение создаёт и рушит по 100 потоков в секунду?

N>>>А это вообще диверсия (если речь не идёт про явно специализированные случаи типа эрланга). Используйте пулы тредов.
R>>Т.е. предлагаешь не инженерное решение, а организационное — автор библиотеки должен постоянно обходить всех клиентов и говорить "Используйте пулы тредов. Пожалуйста."

N>Ему как раз пофиг. Не пофиг — автору конечной программы.



Т.е. ты считаешь нормальным, если документация по Windows или Linux содержала бы фразы типа "Вы не должны создавать более 100 потоков в секунду", "Вы не должны делать более 1000 аллокаций памяти в секунду", "Вы не должны выделать блоки памяти более 10 Мб" ("... потому что мы там кое-чо не доделали, поэтому у Вас может кое-где сбоить") ?!



1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[7]: Lib-ы которым нужен явный init/deinit
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 31.03.08 10:08
Оценка:
Здравствуйте, remark, Вы писали:

R>>>Ну хотя сейчас я уже знаю:

R>>>http://www.rsdn.ru/forum/message/2895408.1.aspx
Автор: remark
Дата: 29.03.08

N>>Как завершается тред? Если форсированным убийством без права пискнуть, то всё плохо по-любому. Если обычным путём, управляемым средой языка (return или исключение), то достаточно объекта со счётчиком и логикой "init/deinit только на переходах счётчика между 0 и 1", устанавливаемого в тред в стиле RAII.
R>Тогда я не понял твоего тезиса... Ты с чем-то несогласен? Или что-то предлагаешь? :xz:
R>Можешь пояснить?

Я говорю, что мне кажется, что проблемы тут по сути нет и не было.

N>>>>Ну или разрешить многократную инициализацию и деинициализацию.

R>>>Если я правильно понял, то речь не об этом. Речь о том, как инициализировать/деинициализировать ресурсы, выделенные для конкретного потока, а не глобальные.
N>>О выполнении init/deinit в контексте именно данного треда, насколько я понимаю, заботится библиотека.
R>О библиотеке как раз и идёт речь. Т.е. ответы типа "а библиотека как-то там это сама сделает" не катят :)))

Ну?

N>>Ему как раз пофиг. Не пофиг — автору конечной программы.

R>Т.е. ты считаешь нормальным, если документация по Windows или Linux содержала бы фразы типа "Вы не должны создавать более 100 потоков в секунду", "Вы не должны делать более 1000 аллокаций памяти в секунду", "Вы не должны выделать блоки памяти более 10 Мб" ("... потому что мы там кое-чо не доделали, поэтому у Вас может кое-где сбоить") ?! :xz:

Мне не хочется отвечать на непонятно откуда почему возникшие додумки типа "мы там кое-чо не доделали", извини уж. Хочешь фантазировать в пространство — пожалуйста, но я в этом не участник.
The God is real, unless declared integer.
Re[8]: Lib-ы которым нужен явный init/deinit
От: remark Россия http://www.1024cores.net/
Дата: 31.03.08 10:32
Оценка:
Здравствуйте, netch80, Вы писали:

N>Здравствуйте, remark, Вы писали:


R>>>>Ну хотя сейчас я уже знаю:

R>>>>http://www.rsdn.ru/forum/message/2895408.1.aspx
Автор: remark
Дата: 29.03.08

N>>>Как завершается тред? Если форсированным убийством без права пискнуть, то всё плохо по-любому. Если обычным путём, управляемым средой языка (return или исключение), то достаточно объекта со счётчиком и логикой "init/deinit только на переходах счётчика между 0 и 1", устанавливаемого в тред в стиле RAII.
R>>Тогда я не понял твоего тезиса... Ты с чем-то несогласен? Или что-то предлагаешь?
R>>Можешь пояснить?

N>Я говорю, что мне кажется, что проблемы тут по сути нет и не было.



Если обязать пользователя вызывать global_init()/global_deinit()/thread_init()/thread_deinit(), то, да, всё замечательно. И мне лично такое решение очень нравится.
Но дискуссия пошла в русло, что типа ручная инициализация/деинициализация — сакс, и библиотека должна эти вещи сама у себя внутри как-то разруливать.
Если ты за ручную инициализацию/деинициализацию, то тебе наверное лучше ответить не мне, а сюда:
http://www.rsdn.ru/forum/message/2888124.1.aspx
Автор: uzhas
Дата: 24.03.08




1024cores &mdash; all about multithreading, multicore, concurrency, parallelism, lock-free algorithms
Re[9]: Lib-ы которым нужен явный init/deinit
От: Sergey Россия  
Дата: 31.03.08 11:19
Оценка:
> S>Нифига. Оно реально не работает. CRT ищет эту секцию у себя, а не во
> всех
> S>принадлежащих процессу модулях. Соответственно, в случае статической
> S>линковки все замечательно, в случае динамической — не работает.
>
> Проверил. Их версия у меня не работает только под release, т.к. линкер
> выкидывает некоторые переменные. А статический или динамический ран-тайм
> не влияет.

Очень странно, что работает, потому что я этим вопросом заинересовался
именно в контексте "а почему не чистятся boost::thread_specific_ptr, если
boost::thread прилинковать статически; вроде ж обещали что теперь работает".
Конфигурация у меня была чуть сложнее, чем простой exe — наличествовали
несколько dll, поторые статически линковались с boost::thread.

> Пофиксил это. Выложил рабочую версию:

> http://www.rsdn.ru/forum/message/2895408.1.aspx
Автор: remark
Дата: 29.03.08


Действительно работает. Разница с бустом, насколько я понимаю — наличие
static __declspec(thread) int volatile use_tls;
В бусте (1.34.1) "__declspec(thread)" мне удалось обнаружить единственный
раз, в комментах. Так же не используется #pragma comment(linker,
"/INCLUDE:__tls_used")

Видимо, желающим линковать статически boost::thread и не иметь при этом
проблем с разрушением tss можно посоветовать вставлять в код #pragma
comment(linker, "/INCLUDE:__tls_used")

Самое смешное, что без __declspec(thread) или __tls_used не заработал даже
вариант со статически прилинкованным рантаймом (компилятор правда под рукой
оказался только от VC2008).

Что интересно — нотификация DLL_THREAD_ATTACH похоже присылается без участия
CRT:
A.exe!on_tls_callback(HINSTANCE__ * __formal=0x002d0000, unsigned long
dwReason=0x00000002, HINSTANCE__ * __formal=0x002d0000) Line 41 C++
ntdll.dll!_LdrpCallInitRoutine@16() + 0x14 bytes
ntdll.dll!_LdrpCallTlsInitializers@8() + 0x5d1ee bytes
ntdll.dll!_LdrpInitializeThread@4() — 0x304b5 bytes
ntdll.dll!__LdrpInitialize@8() + 0x7c bytes
ntdll.dll!_LdrInitializeThunk@8() + 0x10 bytes


Стек при завершении нитки тоже забавный:
> A.exe!on_tls_callback(HINSTANCE__ * __formal=0x002d0000, unsigned long
> dwReason=0x00000003, HINSTANCE__ * __formal=0x002d0000) Line 41 C++
ntdll.dll!_LdrpCallInitRoutine@16() + 0x14 bytes
ntdll.dll!_LdrpCallTlsInitializers@8() + 0x5d1ee bytes
ntdll.dll!_LdrShutdownThread@0() — 0x602da bytes
ntdll.dll!_RtlExitUserThread@4() + 0x2a bytes
A.exe!_endthreadex(unsigned int retcode=0x00000000) Line 414 C
A.exe!_callthreadstartex() Line 348 + 0x15 bytes C
A.exe!_threadstartex(void * ptd=0x00164848) Line 331 C
kernel32.dll!@BaseThreadInitThunk@12() + 0x12 bytes
ntdll.dll!__RtlUserThreadStart@8() + 0x27 bytes

Замена _beginthreadex на CreateThread показала, что on_tls_callback все
равно вызывается, а значит CRT в вызове колбэков участвует только косвенно —
помогая форировать необходимые структуры. О чем, собственно и написано в
комментах в tlssup.c:

/* Start section for TLS callback array examined by the OS loader code.
* If dynamic TLS initialization is used, then a pointer to __dyn_tls_init
* will be placed in .CRT$XLC by inclusion of tlsdyn.obj. This will cause
* the .CRT$XD? array of individual TLS variable initialization callbacks
* to be walked.
*/

_CRTALLOC(".CRT$XLA") PIMAGE_TLS_CALLBACK __xl_a = 0;


Ключевой момент:

_CRTALLOC(".rdata$T")
const IMAGE_TLS_DIRECTORY _tls_used =
{
(ULONG)(ULONG_PTR) &_tls_start, // start of tls data
(ULONG)(ULONG_PTR) &_tls_end, // end of tls data
(ULONG)(ULONG_PTR) &_tls_index, // address of tls_index
(ULONG)(ULONG_PTR) (&__xl_a+1), // pointer to call back array
(ULONG) 0, // size of tls zero fill
(ULONG) 0 // characteristics
};
Posted via RSDN NNTP Server 2.1 beta
Одним из 33 полных кавалеров ордена "За заслуги перед Отечеством" является Геннадий Хазанов.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.