Ответ
При создании нового потока (например, с помощью pthread_create() или std::thread) в рамках существующего процесса операционная система выделяет для него новый регион памяти под стек. Размер стека по умолчанию обычно составляет от 1 до 8 МБ (зависит от ОС и может настраиваться через атрибуты потока).
Ключевое разделение памяти в многопоточном процессе:
- Разделяемые всеми потоками:
- Сегмент кода (
.text) — исполняемые инструкции программы. - Сегмент данных (глобальные и статические переменные).
- Куча (heap) — память, выделяемая через
malloc()/new.
- Сегмент кода (
- Уникальные для каждого потока:
- Стек (stack) — содержит локальные переменные, аргументы функций и информацию о вызовах (call stack).
- Thread-Local Storage (TLS) — область для переменных, объявленных с
thread_localв C++11.
Пример, демонстрирующий разные стеки:
#include <iostream>
#include <thread>
void thread_func() {
int local_to_thread = 42; // Живёт в стеке нового потока
std::cout << "Thread stack address: " << &local_to_thread << 'n';
}
int main() {
int local_to_main = 10; // Живёт в стеке главного потока
std::cout << "Main stack address: " << &local_to_main << 'n';
std::thread t(thread_func);
t.join();
}
// Адреса &local_to_main и &local_to_thread будут значительно различаться. Ответ 18+ 🔞
Э, слушай, вот тебе наглядный пример, чтобы вообще всё стало понятно, как устроено это шапито. Представь, что твой процесс — это большой общий дом, где все живут вместе. Так вот, кухня, гостиная и туалет — это общие зоны для всех. Это как раз сегмент кода, глобальные переменные и куча (heap). Туда все ходят, там всё общее, и если один мудак нагадит в раковину, всем потом расхлёбывать.
А теперь самое интересное — стек. Это типа личная комната у каждого потока. Когда ты создаёшь новый поток через pthread_create() или std::thread, операционка ему выделяет новую, отдельную комнату под его личные вещи. Размер этой комнаты по умолчанию — ну, от 1 до 8 мегабайт, смотря какая ОС и как ты её настроишь. В этой комнате он хранит свои локальные переменные, аргументы функций и всю свою внутреннюю кухню вызовов.
И главное — эти комнаты изолированы. Один поток не может просто так залезть в стек другого и посмотреть, какие у того там int'ы лежат в носках. Это, блядь, святое. А то представь, если бы все лезли друг к другу в стек — был бы пиздец, а не многопоточность.
Короче, расклад по памяти такой:
- Что общее (всё как в коммуналке):
- Код программы (сегмент
.text) — инструкция, как жить, одна на всех. - Глобальные и статические переменные — общий холодильник.
- Куча (
heap) — общая кладовка, куда черезmalloc/newможно складывать что угодно. Вот тут уже можно и подраться, если синхронизации нет.
- Код программы (сегмент
- Что личное (у каждого своя берлога):
- Стек (stack) — личная комната. Твои локальные переменные живут тут.
- Thread-Local Storage (TLS) — это типа запертый ящик в твоей комнате, для переменных с
thread_local. Совсем своё, приватное.
А вот живой пример, чтобы вообще мозг встал на место:
#include <iostream>
#include <thread>
void thread_func() {
int local_to_thread = 42; // Эта переменная живёт в стеке НОВОГО потока
std::cout << "Адрес стека нового потока: " << &local_to_thread << 'n';
}
int main() {
int local_to_main = 10; // А эта — в стеке ГЛАВНОГО потока (main)
std::cout << "Адрес стека main: " << &local_to_main << 'n';
std::thread t(thread_func);
t.join();
}
// Адреса &local_to_main и &local_to_thread будут овердохуища разные.
Запустишь этот код — и увидишь, что адреса этих local переменных отличаются как небо и земля. Потому что они в совершенно разных регионах памяти, в своих собственных стеках. Один поток не дотронется до локальной переменной другого, даже если захочет. Вот и вся магия, ёпта. Никакой чертовщины, просто у каждого своя комната, и слава богу.