// Type your code here, or load an example.
#include <iostream>
#include <numeric>
#include <string>
#include <mutex>
#include <thread>

template <class T>
class   SharedVariable {
private:
    std::mutex  mtx;
    T           data;
public:
    T   Get(void) {
        T       data_cpy;
        std::lock_guard<std::mutex> lck(mtx);
        data_cpy = this->data;
        return data_cpy;
    }
    void Set(const T data) {
        std::lock_guard<std::mutex> lck(mtx);
        this->data = data;
    }
};    

void func(int & i ,std::mutex & mtx) {
    std::lock_guard<std::mutex> lck(mtx);
    int tmp = i;
    std::this_thread::yield();
    i = tmp +1 ;
}

void func2(SharedVariable<int> & sv_int) {
    int tmp = sv_int.Get();
    std::this_thread::yield();
    sv_int.Set(tmp +1);
}

#define TH_NUM 8

void func_test(){
    int x = 0 ;
	std::mutex mtx ;
	bool strt_flag = false;
	std::thread t [TH_NUM];
    for (size_t i = 0 ;i < TH_NUM;++i) { 
        t[i] = std::thread([&]() {
            while(!strt_flag);
            func(x , mtx);
        });

    }
    strt_flag = true;
    for (int i = 0 ;i<TH_NUM ;++i) {
    	
    	t[i].join();
    	
    } 
    std::cout<<"x = "<< x <<std::endl;
}

void func2_test(){
    SharedVariable<int> sv_int;
    sv_int.Set(0);
    std::thread t [TH_NUM];
    bool strt_flag = false;
    for (size_t i = 0 ;i < TH_NUM;++i) { 
        t[i] = std::thread([&]() {
            while(!strt_flag);
            func2(sv_int);
        });
    }
    strt_flag = true;
    for (size_t i = 0 ;i < TH_NUM;++i) { 
        t[i].join();
    }
    std::cout<<"sv_int = "<< sv_int.Get() <<std::endl;
}


int main () {
    func_test();
    func2_test();

    return 0;
}