Что такое поток (thread) в программировании?

«Что такое поток (thread) в программировании?» — вопрос из категории Многопоточность, который задают на 30% собеседований C/C++ Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

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

Зачем нужны потоки в C++?

  • Параллелизм: Использование нескольких ядер CPU для ускорения вычислений.
  • Отзывчивость: Выполнение длительных операций (например, I/O) в фоновом потоке, не блокируя основной поток пользовательского интерфейса.
  • Асинхронная обработка: Одновременное обслуживание множества сетевых подключений или запросов.

Базовый пример с std::thread (C++11 и выше):

#include <iostream>
#include <thread>
#include <chrono>

void threadFunction(int id) {
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    std::cout << "Hello from thread #" << id << " (ID: "
              << std::this_thread::get_id() << ")" << std::endl;
}

int main() {
    std::cout << "Main thread ID: " << std::this_thread::get_id() << std::endl;

    std::thread t1(threadFunction, 1); // Создание и запуск потока
    std::thread t2(threadFunction, 2);

    // Основной поток ждёт завершения t1 и t2
    t1.join();
    t2.join();

    std::cout << "Both threads finished." << std::endl;
    return 0;
}

Критически важные моменты:

  1. Синхронизация: Так как потоки разделяют память, необходим контроль доступа к общим данным для предотвращения состояний гонки (race conditions). Для этого используются:
    • std::mutex, std::lock_guard, std::unique_lock
    • std::atomic типы
    • Условные переменные (std::condition_variable)
  2. Управление жизненным циклом: Поток должен быть либо присоединён (joined) с помощью join() (основной поток ждёт его завершения), либо отсоединён (detached) с помощью detach() (поток выполняется самостоятельно). Невыполнение этого требования до разрушения объекта std::thread приводит к вызову std::terminate.
  3. Проблемы: Взаимные блокировки (deadlocks), инверсия приоритетов, ложное разделение кэша (false sharing).