Создание потоков
1#include <thread>2#include <iostream>34void worker(int id) {5 std::cout << "Thread " << id << " started\n";6 std::this_thread::sleep_for(std::chrono::milliseconds(100));7 std::cout << "Thread " << id << " finished\n";8}910int main() {11 std::thread t1(worker, 1);12 std::thread t2(worker, 2);1314 t1.join(); // Ожидание завершения15 t2.join();1617 return 0;18}
▸Lambda в потоках
1int main() {2 int counter = 0;3 std::mutex mtx;45 std::thread t1([&]() {6 for (int i = 0; i < 1000; ++i) {7 std::lock_guard<std::mutex> lock(mtx);8 ++counter;9 }10 });1112 std::thread t2([&]() {13 for (int i = 0; i < 1000; ++i) {14 std::lock_guard<std::mutex> lock(mtx);15 ++counter;16 }17 });1819 t1.join();20 t2.join();21 std::cout << "Counter: " << counter << "\n"; // 200022}
std::mutex
Mutex (mutual exclusion) обеспечивает эксклюзивный доступ к разделяемому ресурсу.
▸std::lock_guard
RAII-обёртка для mutex. Автоматически разблокирует mutex при выходе из scope.
1class ThreadSafeCounter {2 int count = 0;3 mutable std::mutex mtx;4public:5 void increment() {6 std::lock_guard<std::mutex> lock(mtx);7 ++count;8 }910 int get() const {11 std::lock_guard<std::mutex> lock(mtx);12 return count;13 }14};
▸std::unique_lock
Более гибкая обёртка: поддерживает deferred locking, timed locking и transfer ownership.
1std::mutex mtx;2std::unique_lock<std::mutex> lock(mtx, std::defer_lock);34// Теперь mutex не заблокирован5lock.lock(); // Блокировка6// ... работа ...7lock.unlock(); // Ручная разблокировка8lock.lock(); // Повторная блокировка
std::condition_variable
Condition variable позволяет потокам ожидать наступления условия.
1#include <condition_variable>23std::queue<int> tasks;4std::mutex mtx;5std::condition_variable cv;6bool done = false;78// Producer9void producer() {10 for (int i = 0; i < 10; ++i) {11 {12 std::lock_guard<std::mutex> lock(mtx);13 tasks.push(i);14 }15 cv.notify_one();16 }17 {18 std::lock_guard<std::mutex> lock(mtx);19 done = true;20 }21 cv.notify_all();22}2324// Consumer25void consumer() {26 while (true) {27 std::unique_lock<std::mutex> lock(mtx);28 cv.wait(lock, [] { return !tasks.empty() || done; });2930 while (!tasks.empty()) {31 int task = tasks.front();32 tasks.pop();33 lock.unlock();34 // Обработка задачи35 std::cout << "Processing: " << task << "\n";36 lock.lock();37 }3839 if (done && tasks.empty()) break;40 }41}
std::atomic
Атомарные операции для lock-free программирования.
1#include <atomic>23std::atomic<int> counter{0};45void increment() {6 for (int i = 0; i < 1000; ++i) {7 ++counter; // Атомарная операция8 }9}1011int main() {12 std::thread t1(increment);13 std::thread t2(increment);14 t1.join();15 t2.join();16 std::cout << counter << "\n"; // 200017}
std::future и std::promise
1#include <future>23int compute() {4 return 42;5}67int main() {8 std::future<int> result = std::async(std::launch::async, compute);9 // Другая работа...10 int value = result.get(); // Блокирующее ожидание результата11 std::cout << value << "\n";12}
Советы по многопоточности
Избегайте гонок данных (data races)
Минимизируйте блокировку mutex
Используйте atomic для простых операций
Не блокируйте mutex при вызове функций, которые могут блокироваться
Используйте thread-safe данные структуры
Заключение
Многопоточность в C++предоставляет мощные инструменты для параллельных вычислений. Правильная синхронизация с mutex и condition variables критична для корректной работы. Используйте lock_guard и unique_lock для RAII-управления блокировками.