Потоки против процессов

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

Поток (thread) — это отдельная нить исполнения внутри процесса. У процесса может быть много потоков, и все они разделяют общую память процесса.

Главная идея

Процесс — это «дом» с собственной территорией (адресным пространством). Поток — это «жилец» внутри дома. В одном доме может жить несколько жильцов, и они пользуются общей кухней и гостиной (общей памятью). А вот разные дома (процессы) изолированы заборами.

Зачем нужны потоки? Чтобы делать несколько вещей внутри одной программы параллельно: один поток рисует интерфейс, другой загружает файл, третий считает. И при этом им легко обмениваться данными — память-то общая.

Что общее, а что своё

РесурсОбщий для потоков?
Код (text)да, общий
Куча (heap), глобальные данныеда, общие
Открытые файлыда, общие
Стекнет, у каждого потока свой
Регистры, счётчик команднет, у каждого свои

У каждого потока свой стек и свои регистры — иначе они не могли бы выполнять разный код одновременно. Но куча общая, поэтому потоки видят одни и те же объекты. Отсюда и удобство, и опасность: общая память — источник гонок данных (это тема четвёртого раздела).

Потоки против процессов: сравнение

КритерийПроцессыПотоки
Памятьизолированнаяобщая внутри процесса
Созданиедорожедешевле
Переключениедорожедешевле
Обмен даннымичерез IPCнапрямую через память
Надёжностьсбой одного не валит другихсбой потока может уронить весь процесс

Плюсы и минусы многопоточности

Плюсы: отзывчивость (UI не зависает, пока идёт долгая задача), использование нескольких ядер, лёгкий обмен данными, экономия памяти по сравнению с процессами.

Минусы: сложность — общая память порождает гонки и взаимоблокировки; один упавший поток может обрушить весь процесс; отладка многопоточного кода трудна.

Модели потоков

Потоки бывают пользовательскими (управляет библиотека) и ядерными (управляет ядро). Современные ОС обычно отображают потоки приложения на потоки ядра, что позволяет реально использовать несколько ядер процессора.

Реальный код с потоками

Так выглядит создание потоков на C (POSIX threads). Это системный код — он не запускается в браузере, только подсветка.

#include <pthread.h>

void* worker(void* arg) {
    // работа потока
    return NULL;
}

pthread_t t1, t2;
pthread_create(&t1, NULL, worker, NULL);   // создать поток
pthread_create(&t2, NULL, worker, NULL);
pthread_join(t1, NULL);                     // дождаться завершения
pthread_join(t2, NULL);

Сравним стоимость: процессы или потоки

Смоделируем условную стоимость создания и переключения. Цифры иллюстративные, но порядок верный: потоки заметно дешевле процессов.

process_create = 1000   # условные такты
thread_create  = 100
process_switch = 300
thread_switch  = 50

n = 8  # сколько единиц работы запустить

print(f"{n} процессов: создание {n*process_create}, переключение {n*process_switch}")
print(f"{n} потоков:   создание {n*thread_create}, переключение {n*thread_switch}")

ratio = (n*process_create) / (n*thread_create)
print(f"Создание потоков дешевле в {ratio:.0f} раз")

Вывод:

8 процессов: создание 8000, переключение 2400
8 потоков:   создание 800, переключение 400
Создание потоков дешевле в 10 раз

Итог

  • Поток — нить исполнения внутри процесса; у процесса их может быть много.
  • Потоки разделяют код, кучу и файлы, но имеют свой стек и регистры.
  • Потоки дешевле процессов в создании и переключении.
  • Плата за общую память — риск гонок данных и взаимоблокировок.
  • Сбой потока может уронить весь процесс; процессы изолированы лучше.
Проверьте себя
1. Что потоки одного процесса разделяют между собой?
AСтек и регистры
BКучу (heap), код и открытые файлы
CСчётчик команд
DНичего, потоки полностью изолированы
2. Почему создание потока дешевле создания процесса?
AПоток не нужно планировать
BПотоку не создают новое адресное пространство — он работает в уже существующем
CПоток выполняется без процессора
DПоток не имеет собственного стека
3. В чём риск общей памяти у потоков?
AПамять быстро заканчивается
BВозникают гонки данных и взаимоблокировки
CПотоки не видят данные друг друга
DПамять становится доступна другим процессам
Поддержать проект