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

using namespace std;

// blokada gdy cykl w in/out

class Calc {
public:
    static const int TOKEN_END = 100;
    static const int NUM = 100;
    Calc() : in_(nullptr) {
        data_.push_back(0); //data is not empty at start
        data_.push_back(0);
    }
    void setIn(Calc& p) { in_ = &p; }

    auto read() {
        auto ret = TOKEN_END;
        lock_guard lock(m_);
         if(!data_.empty() ) {
             ret = data_.front();
             data_.pop_front();
         }
         return ret;
    }
    void operator()() {
        if(!in_)
            return;

        for(auto i=0;i<NUM;++i) {
            //tutaj sa obliczenia (kod nieistotny dla zadania)
            //lock_guard lock(m_);
            std::this_thread::sleep_for(std::chrono::milliseconds(10));

            auto x = in_->read();
            if( x != TOKEN_END) {
                //tutaj sa obliczenia (kod nieistotny dla zadania)
                lock_guard lock(m_); // poprawna odpowiedz!
                cout << "X:" << x << endl;
                data_.push_back(x + 1);
            }
        }
    }
private:
    Calc* in_;
    list<int> data_;
    mutex m_;
};

int main() {
    Calc c1, c2;
    c1.setIn(c2);
    c2.setIn(c1);

    thread thrd1( ref(c1) ), thrd2( ref(c2) );

    thrd1.join();    thrd2.join();

    cout << "thrd1: " << c1.read() << endl;
    cout << "thrd2: " << c2.read() << endl;
}
