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

using namespace std;

// wysyla napisy na cout, mozna stoswac w aplikacjach wspolbieznych
class Logger {
public:
	static Logger* getInstance() {
		if(!instance) {
			lock_guard<mutex> lock(m);
			if (!instance)
				instance = new Logger();
		}
		return instance;
	}

	void msg(const string& s) {
		lock_guard<mutex> lock(Logger::m);
		cout << ++counter_ << ":" << s << endl;
	}
private:
	Logger() : counter_(0) {}
	Logger(const Logger&) = delete;

	int counter_;
	static Logger* instance;
	static mutex m;
};

Logger* Logger::instance = nullptr;
mutex Logger::m;


const int N = 1000;

void thread_fun(int idx) {
    for(int i=0;i<N;++i) {
        string m = "Thread " + to_string(idx);
        Logger::getInstance()->msg(m);
    }
}

int main() {
    thread th1( thread_fun, 1);
    thread th2( thread_fun, 2);
    thread th3( thread_fun, 3);
    th1.join(); th2.join(); th3.join();
    return 0;
}
