#include <iostream>
#include <iomanip>
#include <thread>
#include <atomic>
#include <mutex>

using namespace std;

mutex out;

class Thread
{

public:
    template<class Fn, class... Args>
    Thread(Fn&& Fx, Args&&... Ax):
    run(forward<Fn>(Fx), forward<Args>(Ax)...)
    ,check([this](){ this->run.join(); this->isDone = true; })
    ,isDone(false)
    {
    }
    ~Thread(){ check.join(); }
private:
    thread run, check;
public:
    atomic<bool> isDone;
};

void doit(const char * s, int n)
{
    for(int i = 0; i < n; ++i)
    {
        {
            lock_guard<mutex> lock(out);
            cout << s << endl;
        }
        this_thread::sleep_for(10ms);
    }
}

int main(int argc, char * argv[])
{
    try {
        Thread t(doit,"Hello",10);
        Thread g(doit,"Dolly",20);
        for(int i = 0; i < 100; ++i)
        {
            this_thread::sleep_for(10ms);
            {
                int count = 0;
                lock_guard<mutex> lock(out);

                if (t.isDone) { cout << "t done\n"; ++count; }
                if (g.isDone) { cout << "g done\n"; ++count; }
                if (count == 2) break;
            }
        }
    } catch(...) { cerr << "Exception!\n"; }
    cout << "Done!\n";
}