Какие участки памяти создаются при создании потока?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Участки памяти при создании потока
При создании нового потока операционная система выделяет несколько структур памяти, необходимых для его работы и управления. Давайте разберёмся, какие именно.
Стек потока (Thread Stack)
Это самый значительный участок памяти, выделяемый для каждого потока. По умолчанию:
- Linux/Unix: обычно 2-8 МБ
- Windows: обычно 1 МБ
- Настраивается:
pthread_attr_setstacksize()
Стек используется для:
- Локальных переменных функций
- Адресов возврата (return addresses)
- Параметров функций
- Временных данных
#include <pthread.h>
#include <iostream>
void* thread_func(void* arg) {
int local_var = 10; // На стеке потока
return nullptr;
}
int main() {
pthread_t thread;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr, 4 * 1024 * 1024); // 4 МБ
pthread_create(&thread, &attr, thread_func, nullptr);
pthread_join(thread, nullptr);
pthread_attr_destroy(&attr);
}
Thread Control Block (TCB)
ОС создаёт структуру управления потоком, содержащую:
- Идентификатор потока (tid на Linux)
- Состояние потока (running, ready, blocked)
- Приоритет
- Маска сигналов
- Контекст процессора (регистры, program counter)
- Указатель на стек
- Thread-local storage (TLS)
Thread Local Storage (TLS)
Каждый поток получает область памяти для своих локальных данных, специфичных только для этого потока:
__thread int thread_local_var = 0; // Каждый поток имеет свою копию
thread_local static int another_var = 5; // C++11 thread_local
int main() {
std::thread t1([]{ thread_local_var = 1; });
std::thread t2([]{ thread_local_var = 2; });
t1.join();
t2.join();
// Каждый поток имеет свою копию thread_local_var
}
Stack Guard Page
ОС выделяет специальную защитную страницу (обычно 4 КБ) в конце стека для предотвращения переполнения стека:
- Помечена как неадресуемая (non-accessible)
- При попытке доступа генерируется SIGSEGV
- Защита от overflow-атак
Heaps и другие области
Хотя куча (heap) является общей для всех потоков процесса, каждый поток получает:
- Собственные буферы аллокатора (если используется thread-safe аллокатор)
- Локальные структуры синхронизации (мьютексы, условные переменные)
Размеры по умолчанию (Linux x86-64)
Основная память потока:
- Stack: 8 МБ (можно менять)
- TCB: ~1-2 КБ
- TLS: зависит от приложения (обычно 100-500 байт)
- Guard page: 4 КБ
- Итого минимум: ~8 МБ + служебная информация
Пример выделения памяти
#include <thread>
#include <iostream>
int main() {
// При создании std::thread выделяется:
// 1. Stack (8 МБ по умолчанию)
// 2. TCB структура
// 3. TLS область
// 4. Guard page
std::thread t([]{
static thread_local int tls_var = 0;
int stack_var = 42; // На стеке потока
// ...
});
t.join(); // Освобождает все ресурсы потока
return 0;
}
Важные моменты
Проблема с множеством потоков: Если создать 10 000 потоков с стеком по 8 МБ каждый — потребуется 80 ГБ памяти! Поэтому:
- Используются пулы потоков (thread pools)
- Разработчики сокращают размер стека при необходимости
- Применяются асинхронные модели (event loops, io_uring)
Момент выделения:
Память выделяется при вызове pthread_create() или std::thread(), не при запуске работы функции.
Освобождение:
Освобождение происходит при завершении потока или вызове pthread_join()/thread.join(), а не при выходе из области видимости переменной потока.