#include <thread>
#include <chrono>
#include <boost/asio.hpp>
#include <iostream>

using namespace std;

int counter = 0;
mutex m;

void serve( int i) {
    counter += i;
    cout << counter << endl;
}

void serve_m( int i) {
    lock_guard l(m);
    serve(i);
}

void serve_t(int i) {
    this_thread::sleep_for(chrono::milliseconds(10));
    serve(i);
}

void serve_tm(int i) {
    this_thread::sleep_for(chrono::milliseconds(10));
    lock_guard l(m);
    serve(i);
}

void async_no_mutex() {
    boost::asio::io_service io;

    boost::asio::steady_timer t1(io, chrono::milliseconds(10) );
    boost::asio::steady_timer t2(io, chrono::milliseconds(10) );
    boost::asio::steady_timer t3(io, chrono::milliseconds(10) );

    t1.async_wait([&](const boost::system::error_code& error){ serve(1);});
    t2.async_wait([&](const boost::system::error_code& error){ serve(2);});
    t3.async_wait([&](const boost::system::error_code& error){ serve(3);});
    io.run();
}

void async_mutex() {
    boost::asio::io_service io;

    boost::asio::steady_timer t1(io, chrono::milliseconds(10) );
    boost::asio::steady_timer t2(io, chrono::milliseconds(10) );
    boost::asio::steady_timer t3(io, chrono::milliseconds(10) );

    t1.async_wait([&](const boost::system::error_code& error){ serve_m(1);});
    t2.async_wait([&](const boost::system::error_code& error){ serve_m(2);});
    t3.async_wait([&](const boost::system::error_code& error){ serve_m(3);});
    io.run();
}

void threads_no_mutex() {
    thread th1( serve_t, 1 );
    thread th2( serve_t, 2 );
    thread th3( serve_t, 3 );

    th1.join(); th2.join(); th3.join();
}


void threads_mutex() {
    thread th1( serve_tm, 1 );
    thread th2( serve_tm, 2 );
    thread th3( serve_tm, 3 );

    th1.join(); th2.join(); th3.join();
}

int main() {
    counter = 0;
    async_no_mutex();
    counter = 0;
    async_mutex();
    counter = 0;
    threads_no_mutex();
    counter = 0;
    threads_mutex();
    return 0;
}

