привет =) сейчас разбирал исходники crt к VS2008 и появилось несколько вопросов. __declspec(thread) – dynamic initialization в исходниках crt есть файлы tlsdyn.c и tlsdtor.c. код в этих юнитах предназначен для вызова заглушек, которые должны инициализировать динамические __declspec(thread) переменные. проблема в том, что при попытке воспользоваться динамической инициализацией компилятор негодует: Код (Text): обыкновенная, статическая инициализация: __declspec(thread) int id = 2Ah; // fine __declspec(thread) ClassWithoutCtorAndDtor xclass; // fine too динамическая инициализация: __declspec(thread) int id = GetCurrentThreadId(); // error C2482: dynamic initialization of 'thread' data not allowed __declspec(thread) ClassWithCtorOrDtor xclass; // error C2483: object with constructor or destructor cannot be declared 'thread' _ что сказано насчёт этих ошибок в MSDN: _ о`кей, хорошо. но зачем тогда тогда такая поддержка в crt? ведь даже в стартовом коде (__tmainCRTStartup & Co) есть несколько строк, обеспечивающих корректную инициализацию динамических __declspec(thread)-переменных: Код (Text): /* * If we have any dynamically initialized __declspec(thread) * variables, then invoke their initialization for the primary * thread used to start the process, by calling __dyn_tls_init * through a callback defined in tlsdyn.obj. */ if (__dyn_tls_init_callback != NULL && _IsNonwritableInCurrentImage((PBYTE)&__dyn_tls_init_callback)) { __dyn_tls_init_callback(NULL, DLL_THREAD_ATTACH, NULL); } есть какая-нибудь информация насчёт этого? возможно, существует какой-нибудь секретный ключ компилятора? или, может быть, поддержка dynamic __declspec(thread) изначально планировалась, но потом была отменена из-за каких-то неизвестных сложностей реализации? в общем, интересуют как факты, так и просто мысли по поводу всего этого. другие вопросы позже =)
Это Thread Local Storage (TLS) и после декларации значение, обычно, вписывает поток. То есть, компилер хочет видеть "static expression" - то что можно вычеслить at compile time.
uguu~, tls: вычислить во время компиляции, положить в секцию .tls так, чтобы данные оказались между переменными _tls_start и _tls_end и т.д... со статическим_статическим tls компилятор на пару с линкером справляется прекрасно =) а вот динамический_статический tls жевать не хочет: c2482, c2483. вот и стало интересно – могут ли быть некие причины (какие-нибудь особенности ос или vc), из-за которых эта функциональность не может быть реализована? или она реализована, но... но?
Так спроектировано что загрузчик/crt инициализирует такую переменную и следовательно хочет получить значение из .exe образа. Раз так, то значение ты должен отдать компилеру и оно будет в какой-то там секции. Можно ли сделать инициализацию динамической? Да можно, если этот "контракт" (это ABI spec) расширить до таблицы с обработчиками, которые будут вызваны для получения этих иницализаторов. Чичас этого нету. Если хочешь копать, можешь добавить всё это в GNU gcc toolchain и потом расшитить Linux ядро. Бессмысленный разговор...
всего-то и нужно, что научить компилятор делать для инициализации подобных переменных такие же заглушки, какие он уже делает для конструирования глобальных объектов... ладно, похоже, в этой теме сейчас действительно не много смысла... s0larian, спасибо за feedback. =)
ага, отличный вопрос. указатели на заглушки помещаются между переменными '__xd_a' и '__xd_z', в секцию '.CRT'. функция '__dyn_tls_init' проходит по этим указателям, вызывая их. а вот указатель на '__dyn_tls_init' помещается в псевдосекцию '.CRT$XLC', попадая как раз между переменными '__xl_a' и '__xl_z' – прямиком в массив tls-callback'ов. т.е. '__dyn_tls_init' будет вызываться каждый раз при вызове tls-callbacks, и, если (reason == DLL_THREAD_ATTACH), она будет вызывать заглушки. [каждая заглушка инициализирует переменную и регистрирует деинициализатор, который вызывается из tls-callback'а в случае (reason == DLL_THREAD_DETACH или DLL_PROCESS_DETACH)].