Как С++ complier реализует локальное хранилище потоков в С++ 0x
Я искал это в google. Но я ничего не могу с этим поделать.
Есть ли у кого-нибудь какие-либо материалы об этом?
Как С++ complier реализует локальное хранилище потоков в С++ 0x
Я искал это в google. Но я ничего не могу с этим поделать.
Есть ли у кого-нибудь какие-либо материалы об этом?
Прочитайте запись в Википедии.
Потоковое локальное хранилище не является чем-то особенным для С++. Иногда это происходит под разными именами, такими как "TLS" (просто аббревиатура от локального хранилища потоков) или "потоковое хранилище" (TSS).
Большинство операционных систем предоставляют API для доступа к хранилищу на потоках. Например, Windows имеет набор функций API, начиная с "TLS". Под капотом Win32 резервирует специальную область для множества данных на потоке, включая локальное хранилище пользовательских потоков, доступное через определенный регистр процессора (FS на x86). Linux предоставляет потоковое хранилище через API-интерфейсы pthread с именами типа pthread_key_create, и они обычно реализуются с использованием аналогичной техники.
Возможно, ОС не предоставляет никакой поддержки вообще. Однако, если ОС предоставляет уникальный идентификатор потока процесса через API, тогда библиотека времени выполнения С++ может поддерживать что-то концептуально, как std::map<thread_id, per_thread_storage>
внутренне. Конечно, тогда есть проблема того, что per_thread_storage
. Если программа была статически связана, она могла бы быть чем-то вроде указателя на большую структуру со всеми переменными хранилища нитей, объявленными в программе как элементы. Это упрощение, но вы получаете общую идею.
Доступ к переменным локального хранилища, очевидно, не просто чтение или запись в прямом режиме. Это потенциально довольно немного больше, чем это. Если вы собираетесь использовать многопоточное локальное/специфическое хранилище в определенной функции, я бы рекомендовал сначала скопировать указатель на локальную область потока в локальную переменную.
Глобальные переменные (или записываемые статические данные - WSD) обычно хранятся в блоке памяти отдельно от стека, кучи и кода. Блок WSD создается и инициализируется до запуска исполняемого кода.
С++ 0x вводит ключевое слово thread_local
, которое гарантирует, что для каждого потока создается отдельный экземпляр глобальной переменной. Проблема в том, что для каждого потока нужно загружать другой блок.
Следующая трудность заключается в том, что адрес переменной не фиксируется во время связи и отличается для каждого потока.
Вокруг этой проблемы есть два пути. Один из них заключается в том, чтобы компилятор генерировал вызов функции для получения правильного блока, а другой - для изменения ABI для хранения блока TLS в одном из регистров процессора. Затем это можно использовать со смещениями для доступа к правильной переменной thread_local
.
Это отличается от поддержки библиотеки, где ОС хранит одно значение void*
, которое можно использовать, чтобы сохранить указатель на локальный блок потока, который был выделен в куче процесса.
Если вы хотите, чтобы детали gory выглядели здесь.
Вы можете использовать boost:: thread для переносимости TLS на разных платформах. Реализация на каждом из них находится в коде и должна помочь вам понять, как разные системы обрабатывают эту область.