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

В чём разница между процессом и потоком?

1.0 Junior🔥 171 комментариев
#Linux и операционные системы#Многопоточность и синхронизация#Язык C++

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

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

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

В чём разница между процессом и потоком?

Процесс (Process) и поток (Thread) — это разные уровни параллелизма в операционной системе. Процесс — это независимый экземпляр программы со своей памятью, файлами и ресурсами. Поток — это легковесная единица выполнения внутри процесса, которая делит память и ресурсы с другими потоками.

Структура памяти

Процесс имеет собственное адресное пространство:

Процесс 1              Процесс 2
─────────────          ──────────────
|  Code  |             |  Code  |    (не могут видеть
|  Data  |             |  Data  |     друг друга)
| Heap   |             | Heap   |    (разные указатели
| Stack  |             | Stack  |     на одну память = разные)

Программа foo.exe запущена дважды = 2 разных процесса. Каждый видит свою память.

Потоки внутри процесса делят память:

Процесс
──────────────────────
|  Code  |
|  Data  | <- общие для всех потоков
| Heap   |
├─────────────────────
| Stack1 | Thread1    | каждый поток
| Stack2 | Thread2    | имеет свой стек
| Stack3 | Thread3    |

Все потоки одного процесса видят одну копию heap и data секций. Это как несколько людей работают в одном офисе (процесс) и делят стол (память).

Сравнение по параметрам

Параметр         Процесс               Поток
────────────────────────────────────────────────────
Адресное пространство  Отдельное    Общее с другими
Память (Code/Data)     Отдельная    Общая (shared)
Стек (Stack)           Отдельный    Отдельный
Ресурсы (файлы, ...) Отдельные    Общие
Коммуникация     Сложная (IPC)    Простая (shared memory)
Контекстное      Дорогое ~μs     Дешёвое ~нано
переключение
Изоляция         Отличная        Слабая (race conditions)
Время создания   Медленно (мс)    Быстро (μs)
Ошибка в одном   Не влияет      Может убить весь процесс

Контекстное переключение

Процесс:

ОС сохраняет/восстанавливает при переключении:
1. Регистры CPU
2. Счётчик команд (PC)
3. Указатель стека (SP)
4. Таблица виртуальной памяти (TLB flush)
5. Дескрипторы файлов
6. Права доступа

Время: ~1-10 микросекунд

Поток:

ОС сохраняет только:
1. Регистры CPU
2. Счётчик команд
3. Указатель стека

Таблица памяти не меняется (та же!)

Время: ~100-500 наносекунд (в 10-100 раз быстрее)

Race Condition — основная проблема потоков

int counter = 0;  // Shared между потоками

void increment() {
    counter++;  // НЕ атомарно!
}

// Thread 1 и Thread 2 одновременно:
// Операция counter++ = 3 шага:
// 1. Читай counter (value = 0)
// 2. Прибавь 1 (temp = 1)
// 3. Запиши обратно (counter = 1)

// Без синхронизации может быть такая последовательность:
// Thread1: Read (0) ──┐
// Thread2:      Read (0) ──┐
// Thread1:           Inc    ──┐
// Thread2:                 Inc ──┐
// Thread1:                      Write (1)
// Thread2:                              Write (1)
// Результат: counter = 1 вместо 2 ! УТЕЧКА ИНКРЕМЕНТА!

Решение с мьютексом:

std::mutex mtx;
int counter = 0;

void increment() {
    std::lock_guard<std::mutex> lock(mtx);  // Блокировка
    counter++;  // Теперь безопасно
}  // Автоматически разблокируется

Или атомарно:

std::atomic<int> counter(0);

void increment() {
    counter++;  // Атомарная операция, безопасно
}

Создание процесса vs потока

Процесс (Unix/Linux):

#include <unistd.h>

int main() {
    pid_t pid = fork();  // Создаём новый процесс
    
    if (pid == 0) {
        // Дочерний процесс
        std::cout << "Child process" << std::endl;
        exit(0);
    } else if (pid > 0) {
        // Родительский процесс
        std::cout << "Parent process, child PID = " << pid << std::endl;
        wait(nullptr);  // Ждём дочерний процесс
    }
}

Поток (C++11):

#include <thread>

void worker() {
    std::cout << "Worker thread" << std::endl;
}

int main() {
    std::thread t(worker);  // Создаём поток
    t.join();               // Ждём завершения потока
}

Коммуникация между процессами (IPC)

// Процессы не могут напрямую писать в память друг друга
// Нужны специальные механизмы:

// 1. Pipes (конвейеры)
int pipefd[2];
pipe(pipefd);
// pipefd[0] - для чтения, pipefd[1] - для писания

// 2. Shared Memory (разделяемая память)
int shmid = shmget(key, size, IPC_CREAT);
void* addr = shmat(shmid, nullptr, 0);

// 3. Sockets (сокеты)
socket(AF_INET, SOCK_STREAM, 0);

// 4. Message Queues
msgget(key, IPC_CREAT);

Потоки проще:

int shared_var = 0;  // Видна всем потокам

void thread_func() {
    shared_var++;  // Просто читаем/пишем
}

Примеры использования

Процессы нужны когда:

  • Изоляция критична (безопасность, стабильность)
  • Запускаешь внешние программы
  • Долгоживущие воркеры с разными ресурсами
  • Крах одного не должен убить другие
// Web-сервер: каждый клиент в отдельном процессе
while (true) {
    int client_socket = accept(...);
    pid_t pid = fork();
    if (pid == 0) {
        handle_client(client_socket);  // Отдельный процесс
        exit(0);
    }
}

Потоки нужны когда:

  • Быстрая коммуникация между работниками
  • Общее состояние (куча, данные)
  • Частые переключения контекста
  • Высокая производительность
// Thread pool для обработки задач
std::vector<std::thread> workers;
std::queue<Task> task_queue;  // Общая очередь
std::mutex queue_mutex;

for (int i = 0; i < 4; i++) {
    workers.emplace_back([&] {
        while (true) {
            std::lock_guard<std::mutex> lock(queue_mutex);
            if (task_queue.empty()) continue;
            Task t = task_queue.front();
            task_queue.pop();
            process(t);
        }
    });
}

Современный подход

Асинхронное программирование (Futures, async):

#include <future>

int main() {
    // Не создаём явно потоки, пусть STL разбирается
    std::future<int> result = std::async(std::launch::async, []
        {
            return expensive_computation();
        });
    
    int value = result.get();  // Ждём результат
}

Резюме для собеседования

Процесс — тяжёлый, изолированный, со своей памятью. Медленное переключение (~μs), безопасно от ошибок друг друга.

Поток — лёгкий, общая память, быстрое переключение (~нс). Нужна синхронизация (мьютексы, atomic).

Выбор: По умолчанию потоки (быстрее, проще), но если нужна изоляция → процессы.

В чём разница между процессом и потоком? | PrepBro