Управление памятью при использовании потоков

1) Я попытался найти, как будет распределяться память, когда мы будем использовать потоки в программе, но не нашел ответа. Здесь Что и где находятся стек и куча? как стек и куча работают, когда вызывается одна программа. Но что происходит, когда дело доходит до программирования с потоками?

2) Использование параллельной области OpenMP создает потоки, и параллельный код будет выполняться одновременно в каждом потоке. Выделяет ли это больше места в памяти, чем память, занятая тем же кодом при последовательном выполнении?


person Rakesh    schedule 21.01.2015    source источник


Ответы (1)


В общем, да, стеки [пользовательского пространства] - по одному на поток, тогда как куча обычно используется всеми потоками. См., Например, этот вопрос о Linux. Однако в некоторых операционных системах (ОС) на Windows, в частности, даже однопоточное приложение может использовать более одной кучи. Использование OpenMP для потоковой передачи не меняет этих основ, которые в основном зависят от операционной системы. Поэтому, если вы не сузите свой вопрос до конкретной ОС, на этом уровне обобщения нельзя сказать больше.

Поскольку мне лень самому рисовать это, вот сравнительная иллюстрация из Программирование PThreads Николса и др. (1996) введите описание изображения здесь

Несколько более подробная (и, к сожалению, потенциально более запутанная) диаграмма находится в бесплатном LLNL Учебное пособие по программированию потоков POSIX Б. Барни.

И да, как вы правильно подозреваете, выполнение большего количества потоков требует больше памяти стека. Фактически вы можете исчерпать виртуальное адресное пространство процесса с помощью стеки ниток, если их достаточно. В различных реализациях OpenMP есть переменная среды STACKSIZE. (или около), который контролирует, сколько стека OpenMP выделяет для потока.

Что касается вопроса / предложения Z boson о локальном хранилище потоков (TLS): грубо (то есть концептуально) говоря, Локальное хранилище потоков - это куча для каждого потока. Существуют отличия от кучи для каждого процесса в API, используемом для управления им, по крайней мере потому, что каждому потоку нужен свой собственный отдельный указатель на свой собственный TLS, но в основном у вас есть подобный куче фрагмент адресного пространства процесса, который зарезервирован к каждому потоку. TLS не является обязательным, вам не нужно его использовать. OpenMP предоставляет собственную абстракцию / директиву для TLS -подобные постоянные данные для каждого потока, называемые THREADPRIVATE. Необязательно, чтобы OpenMP THREADPRIVATE использовал поддержку TLS операционной системы, однако есть Linux- специализированный документ, в котором говорится, что такая реализация дает наилучшую производительность, по крайней мере, в этой среде.

И вот тонкость (или почему я сказал «грубо говоря», когда сравнивал TLS с кучей по потокам): предположим, что вам нужна куча по потокам, скажем, чтобы уменьшить конкуренцию за блокировку основной кучи. На самом деле вам не нужно хранить всю кучу для каждого потока в TLS каждого потока. Достаточно сохранить в TLS каждого потока отдельный указатель заголовка на кучи, выделенные в общем пространстве для каждого процесса. Идентификация и автоматическое использование куч по потокам в программе (для уменьшения конфликтов блокировок в основной куче) - это чрезвычайно сложная проблема CS. Распределители кучи, которые делают это автоматически, называются масштабируемыми / параллельными [izing] распределителями кучи или около того. Например, Intel TBB предоставляет один такой распределитель, и он можно использовать в вашей программе, даже если вы больше ничего не используете из TBB. Хотя некоторые люди, кажется, считают, что распределитель Intel TBB содержит черную магию, на самом деле он не сильно отличается от вышеупомянутой базовой идеи использования TLS для указания на некоторую локальную кучу потока, которая, в свою очередь, состоит из нескольких двусвязных списков, разделенных по блокам. / object-size, как на следующих диаграммах из Документ Intel о TBB иллюстрирует: введите описание изображения здесь

У IBM есть нечто похожее на AIX 7.1, но немного более сложное. Вы можете указать его (по умолчанию) распределителю использовать фиксированное количество куч для многопоточных приложений, например MALLOCOPTIONS=multiheap:3. AIX 7.1 также имеет другой вариант (который можно объединить с multiheap) _ 4_, что несколько похоже на то, что делает Intel TBB, в том, что он поддерживает поточный кеш освобожденных регионов, из которых будущие запросы на выделение могут обслуживаться с меньшей конкуренцией за глобальную кучу. Помимо этих опций для распределителя по умолчанию, AIX 7.1 также имеет (не по умолчанию) " Распределитель Watson2 ", который" использует специфичный для потока механизм, который использует различное количество структур кучи, которое зависит от поведения программы. Поэтому параметры конфигурации не требуются. " (Но вам нужно явно выбрать этот распределитель с помощью MALLOCTYPE=Watson2.) Работа Watson2 звучит даже ближе к тому, что делает распределитель Intel TBB.

Вышеупомянутые два примера (Intel TBB и AIX), подробно описанные выше, предназначены только как конкретные примеры, но не должны восприниматься как содержащие какой-то эксклюзивный соус. Идея кеширования кучи на поток или процессор / arena / журнал довольно широко распространен. В статье о jemalloc BSDcan цитируется 1998 MS Research как первая систематическая оценка арен для этой цели. Вышеупомянутый документ MS ссылается на веб-страницу ptmalloc как «посещенную 11 мая 1998 г.» и резюмирует работу ptmalloc следующим образом: «Он использует связанный список подкучков, где каждая подкуча имеет блокировку, 128 свободных списков и некоторую память для управления. . Когда потоку необходимо выделить блок, он сканирует список подгрудей и захватывает первую разблокированную, выделяет требуемый блок и возвращается. Если он не может найти разблокированную подкучину, он создает новую и добавляет ее в список. Таким образом, поток никогда не ждет в заблокированной подкуче ".

person Fizz    schedule 21.01.2015
comment
@Respwned Fluff. Для программы переменного тока может быть расположение памяти, как в ‹geeksforgeeks.org / memory-layout-of-c-program ›. Занимает ли каждая копия кода параллельной области для каждого потока некоторое пространство в этой текстовой области процесса? - person Rakesh; 21.01.2015
comment
Это зависит от приложения. Для некоторых приложений код, выполняемый потоками, одинаков; для других приложений каждый поток может быть очень специализированным, поэтому между ними нет фактического совместного использования кода. Но все потоки (по определению) имеют доступ ко всему адресному пространству процесса, поэтому теоретически все могут использовать / совместно использовать один и тот же код. Между прочим, эта проблема совместного использования (или отсутствия совместного использования) кода ортогональна стекам. - person Fizz; 21.01.2015
comment
Я не понял слова «отогональный» для стека. что это означает..? - person Rakesh; 21.01.2015
comment
Это означает, что у вас есть поток на стек независимо от того, выполняют ли потоки один и тот же код или нет. Обратите внимание, что текстовый сегмент является общим и видимым для всех потоков, но это не означает, что на практике все они будут работать в одной и той же области кода. Я добавил диаграмму к ответу и вскоре добавлю ссылку на другой источник (с дополнительными пояснениями). - person Fizz; 21.01.2015
comment
Хороший сюжет, но было бы неплохо также увидеть что-то, что включает в себя локальное хранилище потоков. - person Z boson; 22.01.2015
comment
@Z boson: Я добавил кое-что о TLS. Такими общими темами / вопросами сложно не дойти до кандидатской диссертации, если хочется затронуть все аспекты ... - person Fizz; 22.01.2015
comment
@RespawnedFluff Большое спасибо .. предоставленная ссылка на учебник Б. Барни дала хорошее понимание .. Даже приведенная выше диаграмма очень полезна. Я бы хотел пройти и по другим ссылкам, если вы можете добавить эти ссылки .. Спасибо - person Rakesh; 22.01.2015
comment
Стоит упомянуть, что распределитель памяти в GLIBC (ptmalloc2, если я правильно помню) уже очень давно поддерживает отдельные потоки и некоторые серверные дистрибутивы, например RHEL поставляется с включенной функцией, в то время как другие (в основном настольные) дистрибутивы этого не делают, поскольку это увеличивает объем памяти, занимаемый приложениями. ptmalloc2 использует одну арену на каждое ядро ​​ЦП и в основном свободен от блокировок. - person Hristo Iliev; 22.01.2015
comment
Что меня больше заинтриговало, так это почему безблокирующие маллоки не имеют большого практического влияния. - person Fizz; 22.01.2015
comment
@Hristo Iliev: немного покопавшись, действительно кажется, что ptmalloc был первым (или, по крайней мере, одним из первых) распределителей, которые использовали несколько куч / арен для улучшения многопоточной производительности. Я обновил сообщение тем, что нашел. Спасибо, что подняли этот вопрос. Единственное, что меня беспокоит при добавлении информации, предложенной вами и Z-бозоном, это то, что она будет подавляющей для OP (Ракеш) ... - person Fizz; 22.01.2015
comment
Насколько я понимаю, ответы здесь предназначены для ОП и всех, кто может прийти в будущем. Поэтому совершенно нормально, если в ответе будет больше информации, чем запрошено. - person Hristo Iliev; 22.01.2015