Как компилятор С++ реализует локальное хранилище потоков в С++ 0x?

Как С++ complier реализует локальное хранилище потоков в С++ 0x

Я искал это в google. Но я ничего не могу с этим поделать.

Есть ли у кого-нибудь какие-либо материалы об этом?

Ответ 1

Прочитайте запись в Википедии.

Потоковое локальное хранилище не является чем-то особенным для С++. Иногда это происходит под разными именами, такими как "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. Если программа была статически связана, она могла бы быть чем-то вроде указателя на большую структуру со всеми переменными хранилища нитей, объявленными в программе как элементы. Это упрощение, но вы получаете общую идею.

Доступ к переменным локального хранилища, очевидно, не просто чтение или запись в прямом режиме. Это потенциально довольно немного больше, чем это. Если вы собираетесь использовать многопоточное локальное/специфическое хранилище в определенной функции, я бы рекомендовал сначала скопировать указатель на локальную область потока в локальную переменную.

Ответ 2

Глобальные переменные (или записываемые статические данные - WSD) обычно хранятся в блоке памяти отдельно от стека, кучи и кода. Блок WSD создается и инициализируется до запуска исполняемого кода.

С++ 0x вводит ключевое слово thread_local, которое гарантирует, что для каждого потока создается отдельный экземпляр глобальной переменной. Проблема в том, что для каждого потока нужно загружать другой блок.

Следующая трудность заключается в том, что адрес переменной не фиксируется во время связи и отличается для каждого потока.

Вокруг этой проблемы есть два пути. Один из них заключается в том, чтобы компилятор генерировал вызов функции для получения правильного блока, а другой - для изменения ABI для хранения блока TLS в одном из регистров процессора. Затем это можно использовать со смещениями для доступа к правильной переменной thread_local.

Это отличается от поддержки библиотеки, где ОС хранит одно значение void*, которое можно использовать, чтобы сохранить указатель на локальный блок потока, который был выделен в куче процесса.

Если вы хотите, чтобы детали gory выглядели здесь.

Ответ 3

Вы можете использовать boost:: thread для переносимости TLS на разных платформах. Реализация на каждом из них находится в коде и должна помочь вам понять, как разные системы обрабатывают эту область.