---
# System prepended metadata

title: Untitled

---

## 42-Оповещения о событиях
## happen-before
Тут буквально полный ответ на вопрос
https://github.com/hse-spb-2021-cpp/lectures/blob/961bda076612a58f17ba4f62e506fb281e04e7ec/19-220214/01-model/04-happens-before.md
## Producer-consumer и cond_var
Это некоторая модель, где есть *producer* - который отдаёт данные, и *consumer* - который их должен в онлайн режиме читать и обрабатывать. 
Есть несколько реализаций (код Егора):
1. **Promise and future:**
 ```C++
#include <chrono>
#include <future>
#include <iostream>
#include <string>
#include <thread>

int main() {
    std::promise<std::string> input_promise;
    std::future<std::string> input_future = input_promise.get_future();

    std::thread producer([&]() {
        std::string input;
        std::cin >> input;
        input_promise.set_value(std::move(input));
    });

    std::thread consumer([&]() {
        std::cout << "Consumer started\n";
        std::string input = input_future.get();
        std::this_thread::sleep_for(std::chrono::milliseconds(2000));
        std::cout << "Got string: " << input << "\n";
    });

    consumer.join();
    producer.join();
}
```
Здесь можно увидеть, что *producer* читает данные с ввода и передаёт их в специальную переменную *promise* (коробочку), из которой *consumer* с помощью метода `get()` у переменной типа *future*, который не просто считывает содержимое *promise*, а ждёт, пока туда запишут какое-то значение.
Заметим, что *future* констрактится от *promise* и на самом деле, такая конструкция не способна передавать очередь значений, она лишь работает на "единичных передачках".

2. **Async (так писать не рекомендуется):**
```C++
 std::future<std::string> input_future = std::async([]() {
        std::string input;
        std::cin >> input;
        return input;
    });
```
Это другая реализация *producer*, остальной код такой же. 
*async* - по факту "прячет" в себя *thread* и *promise*. То есть мы таким образом говорим, что эта переменная вычислится в соседнем потоке когда-нибудь. 
Это плохая практика, так как *async* - мы соверешенно не контроллируем, не умеем отключать поток(если он нам стал не нужен)  например.

3. **Mutex-ы (так писать не рекомендуется):**
```C++
 std::mutex m;
    std::string input;
    bool input_available = false;

    std::thread producer([&]() {
        while (true) {
            std::cin >> input;

            std::unique_lock l(m);
            input_available = true;
        }
    });

    std::thread consumer([&]() {
        while (true) {
            std::string input_snapshot;
            {
                std::unique_lock l(m);
                if (!input_available) {
                    continue;
                }
                input_snapshot = input;  // Не хотим, чтобы input изменился, пока мы ждём две секунды.
                input_available = false;
            }  // l.unlock();

            std::this_thread::sleep_for(std::chrono::milliseconds(2000));
            std::cout << "Got string: " << input_snapshot << "\n";
        }
    });

    consumer.join();
    producer.join();
}
```
Идея таже, но вот в цикле *while* у *consumer*  постоянно берётся *mutex* - это сильно жрёт проц + бесполезно, так как на самом деле мы хотим его взять, только когда *producer* нам что-нибудь отправит, чтобы это исправить есть 4-ый способ.

4. **Cond_var** (the coolest):
Что такое *condition_variable*? Это такая переменная которая обладает методами: *.wait(m)* - ждёт, пока от этой же переменной вызовут *notify* на текущий поток, отпускает *mutex* ( *m* ) пока ждёт
*.notify*  -  будит произвольный поток (может всех, может одного) в котором запущен *wait* на этой переменной.
Таким образом, она позволяет усыплять поток и будить его другим потоком.
```C++
#include <chrono>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <string>
#include <thread>

int main() {
    std::mutex m;
    std::string input;
    bool input_available = false;
    std::condition_variable cond;

    std::thread producer([&]() {
        while (true) {
            std::cin >> input;
            std::unique_lock l(m);
            input_available = true;
            cond.notify_one();  // Разбудит один случайный поток. Важно, чтобы это было ему по делу.
        }
    });

    std::thread consumer([&]() {
        while (true) {
            std::unique_lock l(m);
            while (!input_available) {  // while, не if!
                cond.wait(l);
            }
            // Эквивалентная while конструкция, чтобы было сложнее набагать и были понятнее намерения.
            // cond.wait(l, []() { return input_available; });  // "ждём выполнения предиката".
            std::string input_snapshot = input;
            input_available = false;
            l.unlock();

            std::this_thread::sleep_for(std::chrono::milliseconds(2000));
            std::cout << "Got string: " << input_snapshot << "\n";
        }
    });

    consumer.join();
    producer.join();
}
```
Тут после того, как *producer* считал данные и вызыватся *notify_one* у *cond_var*-а и таким образом запускается один случайный поток с *consumer*-ом.
Важно заметить, что  `cond.wait(l)` происходит внутри `while` а не `if`, т.к. существует `spurious wakeup`, когда система может просто так взять и разбудить поток, в таком случае мы бы вышли из `if` и пошли бы дальше, хотя *input* ещё не поступал. 

## Mutable
Это ключевое слово нужно, когда мы хотим менять какую-то переменную в *const* методах класса, в частности, это бывает полезно для *mutex*:
```C++
#include <iostream>
#include <mutex>

struct user {
    mutable std::mutex m_m;
    int m_balance = 1000;

    int balance_up() const {
        std::unique_lock l(m_m);
        return m_balance;
    }
    void get_salary(){
        std::unique_lock l(m_m);
        m_balance+=30;
    }
};
```
В данном коде, функция `balnce()` - потокобезопасная и с *const* квалифаером, если бы *mutex* был не *mutable* - мы бы не могли так сделать.
## Links:
https://github.com/hse-spb-2021-cpp/exercises/tree/master/18-220207/solution - практика на эту тему
https://github.com/hse-spb-2021-cpp/lectures/tree/master/18-220207 - лекция на эту тему.