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

Как можно обмениваться информацией между потоками?

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

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

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

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

Механизмы обмена информацией между потоками в C++

Это одна из ключевых проблем многопоточного программирования. Существует несколько проверенных подходов.

1. Shared Memory + Синхронизация

Разделённая память с механизмами синхронизации — самый простой способ.

#include <thread>
#include <mutex>
#include <vector>

class ThreadSafeQueue {
private:
    std::vector<int> data;
    mutable std::mutex mtx;
    
public:
    void push(int value) {
        std::lock_guard<std::mutex> lock(mtx);
        data.push_back(value);
    }
    
    bool pop(int& value) {
        std::lock_guard<std::mutex> lock(mtx);
        if (data.empty()) return false;
        value = data.back();
        data.pop_back();
        return true;
    }
};

Плюсы: просто, понятно, эффективно для малого количества данных. Минусы: блокировки замедляют работу при частых обращениях.

2. Condition Variables (Переменные условия)

Для синхронизации потоков по событиям. Один поток ждёт сигнала от другого.

#include <condition_variable>
#include <queue>

class ThreadSafeQueue {
private:
    std::queue<int> data;
    mutable std::mutex mtx;
    std::condition_variable cv;
    
public:
    void push(int value) {
        {
            std::lock_guard<std::mutex> lock(mtx);
            data.push(value);
        }
        cv.notify_one();
    }
    
    int wait_and_pop() {
        std::unique_lock<std::mutex> lock(mtx);
        cv.wait(lock, [this] { return !data.empty(); });
        int value = data.front();
        data.pop();
        return value;
    }
};

Плюсы: потоки не "заняты ожиданием". Минусы: сложнее в отладке, риск deadlock.

3. Atomic (Атомарные операции)

Для простых типов данных — безблокировочные и потокобезопасные операции.

#include <atomic>

class SimpleFlag {
private:
    std::atomic<bool> flag{false};
    std::atomic<int> counter{0};
    
public:
    void set_flag() {
        flag.store(true, std::memory_order_release);
    }
    
    bool get_flag() const {
        return flag.load(std::memory_order_acquire);
    }
    
    void increment() {
        counter.fetch_add(1, std::memory_order_relaxed);
    }
};

Плюсы: очень быстро, нет блокировок. Минусы: только для простых типов, требует понимания memory_order.

4. Lock-Free структуры данных

Для высоконагруженных систем используются lock-free очереди без мьютексов.

#include <atomic>

template<typename T>
class LockFreeStack {
private:
    struct Node {
        T data;
        Node* next;
    };
    std::atomic<Node*> head{nullptr};
    
public:
    void push(const T& value) {
        Node* new_node = new Node{value, nullptr};
        Node* old_head = head.load(std::memory_order_acquire);
        do {
            new_node->next = old_head;
        } while (!head.compare_exchange_weak(
            old_head, new_node, 
            std::memory_order_release,
            std::memory_order_acquire
        ));
    }
};

Плюсы: максимальная производительность. Минусы: сложен для понимания.

5. Message Passing (Передача сообщений)

Вместо shared memory используются очереди сообщений. Часто в event-driven архитектурах.

#include <queue>
#include <functional>

class EventBus {
private:
    std::queue<std::function<void()>> events;
    std::mutex mtx;
    
public:
    void post_event(std::function<void()> handler) {
        std::lock_guard<std::mutex> lock(mtx);
        events.push(handler);
    }
    
    void process_events() {
        std::lock_guard<std::mutex> lock(mtx);
        while (!events.empty()) {
            events.front()();
            events.pop();
        }
    }
};

Плюсы: слабая связанность потоков. Минусы: дополнительные накладные расходы на копирование.

Практический совет

Для 95% приложений начните с mutex + condition_variable. Оптимизируйте под lock-free только если профилирование показало узкое место. Используйте RAII для мьютексов, всегда проверяйте condition_variable в цикле, избегайте deadlock, тестируйте с ThreadSanitizer.