Почему потоки разделяют пространство кучи? - PullRequest
20 голосов
/ 23 июля 2010

Каждый из потоков имеет свой собственный стек, но у них общая куча.

Всем ясно, что стек предназначен для локальных переменных / переменных метода, а куча - для переменных экземпляра / класса.

В чем преимущество разделения кучи между потоками.

Несколько потоков работают одновременно, поэтому совместное использование памяти может привести к таким проблемам, как одновременное изменение, взаимное исключение и т. Д. Какое содержимое разделяется потоками в куче.

Почему это так? Почему бы каждому потоку не иметь свою собственную кучу? Кто-нибудь может привести пример из реальной жизни, как разделяемая память используется потоками?

Ответы [ 8 ]

36 голосов
/ 23 июля 2010

Что вы делаете, когда хотите передать данные из одного потока в другой? (Если бы вы никогда этого не делали, вы бы писали отдельные программы, а не одну многопоточную.) Существует два основных подхода:

  • Подход, который вам кажется само собой разумеющимся, - это общая память : за исключением данных, которые имеют веские основания для привязки к потоку (например, стек), все данные доступны для всех потоки. По сути, есть общая куча. Это дает вам скорость : каждый раз, когда поток изменяет некоторые данные, другие потоки могут видеть его. (Ограничение: это не так, если потоки выполняются на разных процессорах: там программист должен особенно усердно работать, чтобы правильно использовать общую память и .) Большинство основных императивных языков, в частности Java и C #, подарите эту модель.

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

  • Двойственный подход - это передача сообщений : каждый поток имеет свое собственное пространство данных; когда поток хочет установить связь с другим потоком, ему необходимо явно отправить сообщение другому потоку, чтобы скопировать данные из кучи отправителя в кучу получателя. В этом случае многие сообщества предпочитают вызывать потоки процессов. Это дает вам безопасность : поскольку поток не может перезаписать память другого потока по прихоти, избегается множество ошибок. Еще одним преимуществом является distribution : вы можете запускать свои потоки на разных машинах без необходимости изменения одной строки в вашей программе. Вы можете найти библиотеки для передачи сообщений для большинства языков, но интеграция имеет тенденцию быть менее хорошей. Хорошие языки для понимания передачи сообщений: Erlang и JoCaml .

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

12 голосов
/ 25 июля 2010

Потому что иначе они были бы процессами.Вот и вся идея потоков, делиться памятью.

3 голосов
/ 23 июля 2010

Процессы - обычно - не разделяют пространство кучи. Для этого есть API, но по умолчанию это отдельные процессы

Потоки разделяют пространство кучи.

Это «практическая идея» - два способа использования памяти - совместно используемая и не разделяемая.

2 голосов
/ 23 июля 2010

Во многих языках / средах выполнения стек (среди прочего) используется для хранения параметров функции / метода и переменных.Если бы поток разделял стек, все было бы очень грязно.

void MyFunc(int a) // Stored on the stack
{
   int b; // Stored on the stack
}

Когда вызов 'MyFunc' завершен, стек сложен, а a и b больше не находятся в стеке.Поскольку потоки не разделяют стеки, для переменных a и b не возникает проблем с потоками.

Из-за природы стека (push / popping) он не очень подходит для поддержания «долгосрочного» состояния или общего состояниячерез вызовы функций.Как это:

int globalValue; // stored on the heap

void Foo() 
{
   int b = globalValue; // Gets the current value of globalValue

   globalValue = 10;
}

void Bar() // Stored on the stack
{
   int b = globalValue; // Gets the current value of globalValue

   globalValue = 20;
}


void main()
{
   globalValue = 0;
   Foo();
   // globalValue is now 10
   Bar();
   // globalValue is now 20
}
1 голос
/ 13 января 2012

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

1 голос
/ 28 июля 2010

Проблема в том, что наличие локальных куч добавляет значительную сложность при очень небольшом значении.

Есть небольшое преимущество в производительности, и оно хорошо обрабатывается TLAB (Thread Local Allocation Buffer), который прозрачно дает вам большинство преимуществ.

1 голос
/ 23 июля 2010

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

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

0 голосов
/ 23 июля 2010

Это потому, что идея потоков - «делиться всем».Конечно, есть некоторые вещи, которыми вы не можете поделиться, например, контекст процессора и стек, но все остальное используется совместно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...