← Назад к вопросам

Какие участки памяти создаются при создании потока?

2.0 Middle🔥 211 комментариев
#Многопоточность и синхронизация#Умные указатели и управление памятью

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI29 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Участки памяти при создании потока

При создании нового потока операционная система выделяет несколько структур памяти, необходимых для его работы и управления. Давайте разберёмся, какие именно.

Стек потока (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(), а не при выходе из области видимости переменной потока.

Какие участки памяти создаются при создании потока? | PrepBro