Почему потоки совместно используют пространство "кучи"?

Потоки у каждого есть их собственный стек, но они совместно используют общую "кучу".

Его ясное всем, что стек для локальных переменных / переменных метода и "кучи", для экземпляра/переменных класса.

Что является преимуществом совместного использования "кучи" среди потоков.

Существует несколько количества потоков, работающих одновременно, так совместное использование памяти может привести к проблемам, таким как параллельная модификация, взаимное исключение и т.д. наверху. Какое содержание совместно используется потоками в "куче".

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

22
задан Nayan Wadekar 25 July 2010 в 05:06
поделиться

7 ответов

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

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

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

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

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

38
ответ дан 29 November 2019 в 03:55
поделиться

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

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

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

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

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
}
2
ответ дан 29 November 2019 в 03:55
поделиться

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

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

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

3
ответ дан 29 November 2019 в 03:55
поделиться

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

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

1
ответ дан 29 November 2019 в 03:55
поделиться

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

12
ответ дан 29 November 2019 в 03:55
поделиться

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

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

1
ответ дан 29 November 2019 в 03:55
поделиться

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

0
ответ дан 29 November 2019 в 03:55
поделиться