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

Как запустить поток?

1.0 Junior🔥 151 комментариев
#Многопоточность и синхронизация

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

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

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

Запуск потока в C++: std::thread

В C++11 появился стандартный способ создания и управления потоками через std::thread из <thread>. Это кроссплатформенное решение работает на Windows, Linux и macOS.

Базовый способ: функция

#include <thread>
#include <iostream>

// Обычная функция
void worker() {
    std::cout << "Thread is running" << std::endl;
}

int main() {
    // Создаём и запускаем поток
    std::thread t(worker);
    
    // Ждём завершения потока
    t.join();
    
    std::cout << "Thread finished" << std::endl;
    return 0;
}

Вывод:

Thread is running
Thread finished

Передача параметров

#include <thread>
#include <iostream>

void worker(int id, const std::string& name) {
    std::cout << "Thread " << id << ": " << name << std::endl;
}

int main() {
    // Передаём параметры после функции
    std::thread t1(worker, 1, "Alice");
    std::thread t2(worker, 2, "Bob");
    
    t1.join();  // Ждём первого
    t2.join();  // Ждём второго
    
    return 0;
}

Вывод:

Thread 1: Alice
Thread 2: Bob

Лямбда-функция

#include <thread>
#include <iostream>

int main() {
    int value = 42;
    
    // Лямбда с захватом переменных
    std::thread t([value]() {
        std::cout << "Value: " << value << std::endl;
    });
    
    t.join();
    return 0;
}

Методы класса

#include <thread>
#include <iostream>

class Worker {
public:
    void do_work(int id) {
        std::cout << "Worker " << id << " is working" << std::endl;
    }
};

int main() {
    Worker w;
    
    // Передаём объект, метод и параметры
    std::thread t(&Worker::do_work, &w, 1);
    
    t.join();
    return 0;
}

Функтор (объект функции)

#include <thread>
#include <iostream>

class ThreadTask {
public:
    void operator()(int value) {
        std::cout << "Task with value: " << value << std::endl;
    }
};

int main() {
    // Осторожно с копированием!
    std::thread t(ThreadTask(), 100);
    
    t.join();
    return 0;
}

Множество потоков

#include <thread>
#include <vector>
#include <iostream>

void worker(int id) {
    std::cout << "Thread " << id << std::endl;
}

int main() {
    std::vector<std::thread> threads;
    
    // Создаём 5 потоков
    for (int i = 0; i < 5; i++) {
        threads.emplace_back(worker, i);
    }
    
    // Ждём всех
    for (auto& t : threads) {
        t.join();
    }
    
    return 0;
}

RAII для потоков

#include <thread>
#include <iostream>

class ThreadGuard {
private:
    std::thread t;

public:
    template<typename Function>
    ThreadGuard(Function f) : t(f) {}
    
    ~ThreadGuard() {
        if (t.joinable()) {
            t.join();  // Автоматический join при выходе
        }
    }
};

int main() {
    {
        ThreadGuard g([]() { std::cout << "Working" << std::endl; });
    }  // Поток ждёт завершения в деструкторе
    
    return 0;
}

Переход в фоновый режим (detach)

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

void background_task() {
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::cout << "Background task done" << std::endl;
}

int main() {
    std::thread t(background_task);
    
    // Отделяем поток - он работает независимо
    t.detach();
    
    // Основной поток продолжает
    std::cout << "Main thread continues" << std::endl;
    
    // Важно: дождитесь завершения перед выходом!
    std::this_thread::sleep_for(std::chrono::seconds(2));
    
    return 0;
}

Вывод:

Main thread continues
Background task done

Захват переменных в лямбде

#include <thread>
#include <iostream>

int main() {
    int x = 10;
    int y = 20;
    
    // [=] — захват всех по значению
    std::thread t1([=]() {
        std::cout << "x=" << x << ", y=" << y << std::endl;
    });
    t1.join();
    
    // [&] — захват всех по ссылке (опасно!)
    std::thread t2([&]() {
        std::cout << "x=" << x << ", y=" << y << std::endl;
    });
    t2.join();
    
    // [=, &y] — захват x по значению, y по ссылке
    std::thread t3([=, &y]() {
        std::cout << "x=" << x << ", y=" << y << std::endl;
    });
    t3.join();
    
    return 0;
}

Синхронизация потоков: mutex

#include <thread>
#include <mutex>
#include <iostream>

int counter = 0;
std::mutex m;

void increment() {
    for (int i = 0; i < 1000; i++) {
        std::lock_guard<std::mutex> lock(m);  // RAII блокировка
        counter++;  // Безопасно
    }
}

int main() {
    std::thread t1(increment);
    std::thread t2(increment);
    
    t1.join();
    t2.join();
    
    std::cout << "Counter: " << counter << std::endl;  // 2000
    return 0;
}

Передача данных между потоками: условная переменная

#include <thread>
#include <mutex>
#include <condition_variable>
#include <iostream>
#include <queue>

std::queue<int> data_queue;
std::mutex m;
std::condition_variable cv;
bool ready = false;

void producer() {
    std::lock_guard<std::mutex> lock(m);
    data_queue.push(42);
    ready = true;
    cv.notify_one();  // Пробудить потребителя
}

void consumer() {
    std::unique_lock<std::mutex> lock(m);
    cv.wait(lock, []() { return ready; });  // Ждём сигнала
    
    int value = data_queue.front();
    data_queue.pop();
    std::cout << "Received: " << value << std::endl;
}

int main() {
    std::thread p(producer);
    std::thread c(consumer);
    
    p.join();
    c.join();
    
    return 0;
}

ID потока и процессорные ядра

#include <thread>
#include <iostream>

int main() {
    // Получить ID текущего потока
    std::cout << "Main thread ID: " << std::this_thread::get_id() << std::endl;
    
    std::thread t([]() {
        std::cout << "Worker thread ID: " << std::this_thread::get_id() << std::endl;
    });
    
    // Количество логических ядер
    unsigned int cores = std::thread::hardware_concurrency();
    std::cout << "Available cores: " << cores << std::endl;
    
    t.join();
    return 0;
}

Обработка исключений в потоках

#include <thread>
#include <iostream>

void risky_task() {
    throw std::runtime_error("Something went wrong!");
}

int main() {
    std::thread t(risky_task);
    
    try {
        t.join();  // Исключение выбросится здесь!
    } catch (const std::exception& e) {
        std::cout << "Exception caught: " << e.what() << std::endl;
    }
    
    return 0;
}

Ошибка: забыли join() или detach()

#include <thread>
#include <iostream>

int main() {
    {
        std::thread t([]() { std::cout << "Hello" << std::endl; });
        // БЕЗ t.join() — программа завершится аварийно!
        // t.join();  // Нужно добавить
    }  // Ошибка: terminate called!
    
    return 0;
}

Правильный паттерн

#include <thread>
#include <vector>

int main() {
    std::vector<std::thread> threads;
    
    // Создание
    for (int i = 0; i < 4; i++) {
        threads.emplace_back([i]() {
            // Работа
        });
    }
    
    // Ожидание
    for (auto& t : threads) {
        if (t.joinable()) {
            t.join();
        }
    }
    
    return 0;
}

Вывод

  • std::thread(function, args) — создание и запуск
  • join() — ждём завершения потока
  • detach() — отделяем поток (осторожно!)
  • mutex + lock_guard — синхронизация доступа
  • condition_variable — сигналы между потоками
  • Всегда join() или detach() перед выходом
  • Используй RAII для гарантированного join()
  • hardware_concurrency() — количество ядер для оптимизации