#include <iostream>
#include <chrono>
#include <thread>
#include <atomic>
using namespace std;
using namespace std::chrono;

struct peterson_lock {
    std::atomic<bool> flag[2] = {false, false};
    std::atomic<int> turn = 0;

    void lock(int self) {
        int other = 1 - self;
        // Declare my intent
        flag[self].store(true, std::memory_order_seq_cst);
        // Yield to other thread
        turn.store(other, std::memory_order_seq_cst);
        // Wait if the other thread has intent and it's their turn
        while (flag[other].load(std::memory_order_seq_cst) &&
               turn.load(std::memory_order_seq_cst) == other)
            ;
    }

    void unlock(int self) {
        // Release my intent
        flag[self].store(false, std::memory_order_seq_cst);
    }
};

int main() {
    uint64_t counter = 0;
    peterson_lock mutex;

    auto f = [&](int id) {
        for (uint64_t i = 0; i < 1'000'000; ++i) {
            mutex.lock(id);
            ++counter;
            mutex.unlock(id);
        }
    };

    {
        jthread t0 { f, 0 };  // self=0, other=1
        jthread t1 { f, 1 };  // self=1, other=0
    }

    cout << "result: " << counter << '\n';
}
